Codeforces 1483A/1484C

Codeforces Round #709 (Div. 1, based on Technocup 2021 Final Round) A. Basic Diplomacy
Codeforces Round #709 (Div. 2, based on Technocup 2021 Final Round) C. Basic Diplomacy


题意

Aleksey有(n)个朋友以及(m)天假期

每一天他都想和一个朋友一起玩

(i)天有(k_i)个朋友有时间跟他玩

如果有某个朋友在这(m)天中被邀请超过(lceil frac m 2 ceil)次,其他朋友会觉得被冒犯到

为了不让任何一个朋友感觉被冒犯,试找到一个合理方案

限制

(1le Tle 10^4)

(1le n,mle 10^5)

(1le k_ile n)

(sum nle 10^5, sum mle 10^5, sum k_i le 2cdot 10^5)




思路

赛事直接开C,明显就是道类二分图匹配,没多想直接开网络流莽过去了,所以 这篇题解只讨论网络流解法


提出题意关键词:每一天选一个朋友,每天只有(k_i)个朋友可选,每个朋友最多选(lceil frac m 2 ceil)

故可以将每一天看作二分图左侧点,每个朋友看作二分图右侧点

并让每一天编号为(1sim m),每个朋友编号(m+1sim m+n)

每一天只能选一个朋友,可以让源点向每一天连一条流量为(1)的边来限制

每天只有(k_i)个朋友可选,说明每天可以向(k_i)个不同的朋友连一条流量为(1)的边

每个朋友最多选(lceil frac m 2 ceil)次,故每个朋友向汇点连一条流量为(lceil frac m 2 ceil)的边来限制

建图完毕后直接跑最大流,如果最大流量为(m),则表示(m)天均匹配到了一个朋友,否则直接输出(NO)

然后在残量网络上寻找有向边((u,v)),如果这条边连接的是(天->朋友)且流量不为(0),则说明第(u)天匹配第(v)个朋友,最后输出即可




代码

(670ms/2000ms)

#include<bits/stdc++.h>
using namespace std;

const int maxn=100050,maxm=400050;
const int INF=0x3f3f3f3f;

struct edge{
    int u,v,cap,flow;
    edge(){}
    edge(int u,int v,int cap,int flow):u(u),v(v),cap(cap),flow(flow){}
}eg[maxm<<1];
int tot,dis[maxn<<1],cur[maxn<<1];
vector<int> tab[maxn<<1];
void init(int n){
    tot=0;
    while(n)tab[n--].clear();
}
void addedge(int u,int v,int cap){
    tab[u].push_back(tot);
    eg[tot++]=edge(u,v,cap,0);
    tab[v].push_back(tot);
    eg[tot++]=edge(v,u,0,0);
}
int bfs(int s,int t){
    queue<int> q;
    q.push(s);
    memset(dis,INF,sizeof dis);
    dis[s]=0;
    while(!q.empty()){
        int h=q.front(),i;
        q.pop();
        for(i=0;i<tab[h].size();i++){
            edge &e=eg[tab[h][i]];
            if(e.cap>e.flow&&dis[e.v]==INF){
                dis[e.v]=dis[h]+1;
                q.push(e.v);
            }
        }
    }
    return dis[t]<INF;
}
int dfs(int x,int maxflow,int s,int t){
    if(x==t||maxflow==0)
        return maxflow;
    int flow=0,i,f;
    for(i=cur[x];i<tab[x].size();i++){
        cur[x]=i;
        edge &e=eg[tab[x][i]];
        if(dis[e.v]==dis[x]+1&&(f=dfs(e.v,min(maxflow,e.cap-e.flow),s,t))>0){
            e.flow+=f;
            eg[tab[x][i]^1].flow-=f;
            flow+=f;
            maxflow-=f;
            if(maxflow==0)
                break;
        }
    }
    return flow;
}
int dinic(int s,int t){
    int flow=0;
    while(bfs(s,t)){
        memset(cur,0,sizeof(cur));
        flow+=dfs(s,INF,s,t);
    }
    return flow;
}

int ans[maxn];

void solve()
{
    int n,m;
    cin>>n>>m;
    init(m+n+2);
    for(int i=1;i<=m;i++)
    {
        int t;
        cin>>t;
        while(t--)
        {
            int j;
            cin>>j;
            addedge(i,j+m,1); //第i天向第j个朋友连边
        }
        addedge(n+m+1,i,1); //源点向第i天连边
    }
    for(int i=1;i<=n;i++)
        addedge(i+m,n+m+2,(m+1)/2); //第i个朋友向汇点连边
    if(dinic(n+m+1,n+m+2)==m) //m个点全都能完成匹配
    {
        cout<<"YES
";
        for(int i=0;i<tot;i+=2)
        {
            if(eg[i].u<=m&&eg[i].flow) //残量网络中如果这条边被使用
                ans[eg[i].u]=eg[i].v-m;
        }
        for(int i=1;i<=m;i++)
            cout<<ans[i]<<' ';
        cout<<'
';
    }
    else
        cout<<"NO
";
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    solve();
    return 0;
}

https://blog.csdn.net/qq_36394234/article/details/115068102

原文地址:https://www.cnblogs.com/stelayuri/p/14580143.html