网络流最大流--luogu2756 飞行员配对方案问题

传送门

一道二分图最大匹配裸题···但既然czq讲网络流就用最大流做一下吧···

设源点s,汇点t

从s向m个外籍连容量为1的边,m个外籍向对应的搭档连容量为1的边,再从n-m个英国向t连容量为1的边

 

然后跑个最大流就行了

这儿是czq骚气的dinic模板,跑挺快的

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define N 105
#define M 50000
#define INF 0x3f3f3f3f
using namespace std;
int n,m,cnt=1,head[N],s,t,dep[N],cur[N],ans;

inline int rd(){
    int x=0,f=1;char c=' ';
    while(c<'0' || c>'9') {if(c=='-')f=-1;c=getchar();}
    while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
    return x*f;
}
struct EDGE{
    int to,nxt,w;
}edge[M];

inline void add(int x,int y,int z){
    edge[++cnt].to=y;
    edge[cnt].nxt=head[x];
    edge[cnt].w=z;
    head[x]=cnt;
}

inline bool bfs(int s,int y){
    memset(dep,0,sizeof dep);
    queue<int> q;
    while(!q.empty()) q.pop();
    q.push(s); dep[s]=1;
    while(!q.empty()){
        int u=q.front(); q.pop();
        for(int i=head[u];i;i=edge[i].nxt){
            int v=edge[i].to;
            if(dep[v] || !edge[i].w) continue;
            dep[v]=dep[u]+1; q.push(v);
        }
    }
    return dep[t];
}

inline int dfs(int x,int flow,int t){
    if(x==t) return flow;
    int used=0,tmp;
    for(int i=cur[x];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(dep[v]!=dep[x]+1) continue;
        tmp=dfs(v,min(flow-used,edge[i].w),t);
        edge[i].w-=tmp,edge[i^1].w+=tmp; used+=tmp;
        if(used==flow) return flow;
        if(edge[i].w) cur[x]=i;
    }
    if(!used) dep[x]=-1;
    return used;
}

inline int dinic(int s,int t){
    int ret=0;
    while(bfs(s,t)){
        memcpy(cur,head,sizeof (head));
        ret+=dfs(s,INF,t);
    }
    return ret;
}

int main(){
    m=rd();n=rd(); s=0,t=n+1;
    for(int i=1;i<=m;i++) add(s,i,1),add(i,s,0);
    for(int i=m+1;i<=n;i++) add(i,t,1),add(t,i,0);
    while(1){
        int a=rd(),b=rd();
        if(a==-1 && b==-1) break;
        add(a,b,1); add(b,a,0);
    }
    ans=dinic(s,t);
    if(ans==0) return cout<<"No Solution!"<<endl,0;
    printf("%d\n",ans);
    for(int u=1;u<=m;u++)
        for(int i=head[u];i;i=edge[i].nxt){
            int v=edge[i].to; if(v==s) continue;
            if(edge[i^1].w) printf("%d %d\n",u,v);
        }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值