Codeforces 709 C Basic Diplomacy 贪心/网络流二分图匹配

链接https://codeforces.com/contest/1484/problem/C

题意
有m天和n个朋友,给出每一天哪些朋友是空闲的,每天邀请一个朋友,不能有朋友的出现次数超过 m 2 \frac{m}{2} 2m,输出任一答案,如果没有答案输出NO。

思路一:贪心

优先选择空闲朋友少的天,对于每一天选择出现次数最少的朋友。

代码:

#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn = 100005;
vector<int> f[maxn];
int vis[maxn];
int ans[maxn];
 
int main()
{
    
    
    int t,n,m,k;
    cin>>t;
    while (t--)
    {
    
    
        pair<int,int> so[maxn]; 
        cin>>n>>m;
        int ff,flag = 1;
        memset(vis,0,sizeof(vis));
        memset(ans,0,sizeof(ans));
        for(int i = 1; i <= m; i++){
    
    
            f[i].clear();
            cin>>k;
            so[i].first = k;
            so[i].second = i;
            for(int j = 1;j <= k; j++){
    
    
                cin>>ff;
                f[i].push_back(ff);
            }
        }
        sort(so + 1,so + m + 1);
        // for(int i = 1;i <= m;i++)
        //     cout<<so[i].second<<endl;
        // cout<<"**"<<endl;
        int no = INF;
        int po = 0;
        for(int c = 1;c <= m ;c++){
    
    
            int i = so[c].second;
            if(f[i].size() == 1)
                po = f[i][0];
            else{
    
    
                no = INF;
                for(int j = 0;j < f[i].size(); j++){
    
    
                    int v = f[i][j];
                    if(vis[v] < no){
    
    
                        no = vis[v];
                        po = v;
                    }
                }
            }
            ans[i] = po;
            vis[po]++;
            if(vis[po] > (m + 1) / 2){
    
    
                flag = 0;
                break;
            }
        }
        if(flag){
    
    
            cout<<"YES"<<endl;
            for(int i = 1;i <= m - 1; i++)
                cout<<ans[i]<<" ";
            cout<<ans[m]<<endl;
        }
        else
            cout<<"NO"<<endl;
    }
    return 0;
}

思路二
可以把这个题目当做一个网络流来做。

将天数作为编号为1~m的点,朋友作为编号为m+1~m+n的点,再添加一个起始s点为n+m+1,终点t为s+1,转化为二分图匹配。

对于所有的起始点和天数点,连一条流量为1的边,对应的天数和朋友连一条流量为1的边,为了满足次数小于 m 2 \frac{m}{2} 2m,让所有朋友和终点的连边的流量为 m 2 \frac{m}{2} 2m

对这个图求他的最大匹配,如果匹配等于m说明有解,该天对应的答案就是两个点之间权值变为0的点。

一开始用的FF算法,结果超时了,FF的算法时间复杂度是 O ( F E ) O(FE) O(FE),不适用于流量太大的网络,换成了dinic

代码(dinic)

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
#define INF 0x3f3f3f3f
struct  edge
{
    
    
    int to,cap,rev;
    void add(int a,int b,int c){
    
    
        to = a,cap = b,rev = c;
    }
};

int level[maxn],iter[maxn],ans[maxn];
vector<edge> g[maxn];

void add_edge(int u,int v,int cap){
    
    
    edge e1,e2;
    e1.add(v,cap,g[v].size());
    g[u].push_back(e1);
    e2.add(u,0,g[u].size() - 1);
    g[v].push_back(e2);
}

void bfs(int s)
{
    
    
    memset(level,-1,sizeof(level));
    queue<int> q;
    level[s] = 0;
    q.push(s);
    while (!q.empty())
    {
    
    
        int u = q.front();
        q.pop();
        for(int i = 0;i < g[u].size(); i++){
    
    
            edge &e = g[u][i];
            if(e.cap > 0 && level[e.to] < 0){
    
    
                level[e.to] = level[u] + 1;
                q.push(e.to);
            }
        }
    }
    
}



int dfs(int u,int t,int f){
    
    
    if(u == t)
        return f;
    for(int &i = iter[u];i < g[u].size() ;i++){
    
    
        edge &e = g[u][i];
        if(e.cap > 0 && level[u] < level[e.to]){
    
    
            int d = dfs(e.to,t,min(f,e.cap));
            // cout<<d<<endl;
            if(d > 0){
    
    
                e.cap -= d;
                g[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}



int max_flow(int s,int t){
    
    
    int flow = 0;
    for(;;){
    
    
        bfs(s);
        if(level[t] < 0){
    
    
            return flow;
            cout<<"flow"<<flow<<endl;
        }
        memset(iter,0,sizeof(iter));
        int f;
        while(f = dfs(s,t,INF) > 0)
            flow += f;
    }
    return flow;
}


void init(int x)
{
    
    
    for(int i = 1;i <= x; i++)
        g[i].clear();
    // memset(ans,0,sizeof(ans));
}

int main()
{
    
    
    int T,n,m;
    cin>>T;
    while (T--)
    {
    
    
        int k,j,s,t;
        cin>>n>>m;
        s = n + m + 1,t = s + 1;
        init(t);
        for(int i = 1;i <= m; i++){
    
    
            cin>>k;
            while(k--){
    
    
                cin>>j;
                add_edge(i,m + j,1);
            }
            add_edge(s,i,1);
        }
        for(int i = 1; i <= n; i++)
            add_edge(m + i,t,(m + 1) / 2);
        int an = max_flow(s,t);
        // cout<<an<<endl;
        if(an == m){
    
    
            cout<<"YES"<<endl;
            for(int i = 1; i <= m; i++){
    
    
                for(int j = 0;j < g[i].size(); j++){
    
    
                    if(g[i][j].cap == 0 )
                        ans[i] = g[i][j].to - m ;
                }
            }
            for(int i = 1;i <= m; i++)
                cout<<ans[i] <<" ";
            cout<<endl;
        }
        else
            cout<<"NO"<<endl;;
    }
    
    return 0;
}

超时的FF也贴一下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;
#define INF 0x3f3f3f3f
struct  edge
{
    
    
    int to,cap,rev;
    void add(int a,int b,int c){
    
    
        to = a,cap = b,rev = c;
    }
};

vector<edge> g[maxn];
int vis[maxn],ans[maxn];
int T,n,m,k;

void add(int u,int v,int cap){
    
    
    edge e1,e2;
    e1.add(v,cap,g[v].size());
    g[u].push_back(e1);
    e2.add(u,0,g[u].size() - 1);
    g[v].push_back(e2);
}

int dfs(int u,int t,int f)
{
    
    
    if(u == t)
        return f;
    vis[u] = 1;
    for(int i = 0;i < g[u].size(); i++){
    
    
        edge &e = g[u][i];
        // cout<<e.to<<endl;
        if(!vis[e.to] && e.cap > 0){
    
    
            int d = dfs(e.to,t,min(f,e.cap));
            if(d > 0){
    
    
                e.cap -= d;
                g[e.to][e.rev].cap += d;
                // cout<<d<<endl;
                return d;   
            }
        }
    }
    // puts("0");
    return 0;
}

int max_flow(int s,int t)
{
    
    
    int res = 0;
    for(;;){
    
    
        memset(vis,0,sizeof(vis));
        int f = dfs(s,t,INF);
        if(f == 0) return res;
        res += f;
    }
}

void init(int x)
{
    
    
    for(int i = 1;i <= x; i++)
        g[i].clear();
    // memset(ans,0,sizeof(ans));
}

int main()
{
    
    
    ios::sync_with_stdio(false);
    cin>>T;
    while(T--){
    
    
        int f;
        cin>>n>>m;
        int s = n + m + 1,t = s + 1;
        // cout<<s<<t<<endl;
        init(t);
        for(int i = 1;i <= m; i++){
    
    
            cin>>k;
            for(int j = 1;j <= k; j++){
    
    
                cin>>f;
                add(i, f + m,1);
            }
             add(s,i,1);
        }
        for(int i = 1;i <= n; i++)
            add(m + i, t, (m + 1) / 2);
        int an = max_flow(s,t);
        // cout<<an<<endl;
        if(an == m){
    
    
            cout<<"YES"<<endl;
            for(int i = 1; i <= m; i++){
    
    
                for(int j = 0;j < g[i].size(); j++){
    
    
                    if(g[i][j].cap == 0 )
                        ans[i] = g[i][j].to - m ;
                }
            }
            for(int i = 1;i <= m; i++)
                cout<<ans[i] <<" ";
            cout<<endl;
        }
        else
             cout<<"NO"<<endl;

    }
}

猜你喜欢

转载自blog.csdn.net/u011612364/article/details/115285694
709