网络流二十四题之飞行员配对问题
先上题目传送门
很明显的一个二分图,用匈牙利算法也可以轻松水过,但既然是网络流二十四题,当然是用网络流的算法才对嘛。
数据很小,而且基本没什么思维难度,在外籍飞行员与英国飞行员之间连边形成一个图,然后建一个超级源点和一个超级汇点,再跑dinic或ISAP就可以了。
至于输出配对的问题,只需要扫一边每一条正边(千万不能扫负边),判断改变的反向边容量是否大于0,如果大于0,就输出该边连的两个点。
很水吧?
上代码(这里我用的dinic算法):
#include<cstdio> #include<queue> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> #include<iostream> #define inf 1e9 using namespace std; const int N=505; const int M=500050; int n,m,ans,start,endd; int head[N],size=1,cur[N]; int depth[N]; struct Node{ int from,to,val,next; }edge[M<<1]; inline int read() { char ch=getchar();int num=0;bool flag=false; while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();} while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();} return flag?-num:num; } inline void add(int x,int y,int z) { edge[++size].from=x; edge[size].to=y; edge[size].val=z; edge[size].next=head[x]; head[x]=size; } inline void add_edge(int x,int y) {add(x,y,1);add(y,x,0);} void ready() { memset(head,-1,sizeof(head)); m=read();n=read(); start=0;endd=n+1; for(int i=1;i<=m;i++) add_edge(start,i); int x=read();int y=read(); while(x!=-1&&y!=-1){ add_edge(x,y); x=read();y=read(); } for(int i=m+1;i<=n;i++) add_edge(i,endd); } inline bool bfs() { queue<int>team; memset(depth,0,sizeof(depth)); depth[start]=1;team.push(start); while(!team.empty()){ int x=team.front();team.pop(); for(int i=head[x];i!=-1;i=edge[i].next){ int y=edge[i].to; if(depth[y]==0&&edge[i].val>0){ depth[y]=depth[x]+1; team.push(y); } } } return depth[endd]>0?true:false; } inline int dfs(int u,int flow) { if(u==endd||flow==0)return flow; for(int& i=cur[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(edge[i].val>0&&depth[v]==depth[u]+1){ int ka=dfs(v,min(edge[i].val,flow)); if(ka>0){ edge[i].val-=ka; edge[i^1].val+=ka; return ka; } } } return 0; } void work() { while(bfs()){ for(int i=start;i<=endd;i++) cur[i]=head[i]; while(int d=dfs(start,inf)) ans+=d; } } void solve() { if(ans==0) {cout<<"No Solution!"; return ;} printf("%d\n",ans); for(int i=0;i<=size;i+=2){ int x=edge[i].from; int y=edge[i].to; if(x==start||y==start) continue; if(x==endd||y==endd) continue; if(edge[i^1].val>0){ printf("%d %d\n",x,y); } } } int main() { ready(); work(); solve(); return 0; }
蒟蒻写博客不易,如果有误还请大佬们提出
如需转载,请署名作者并附上原文链接,蒟蒻非常感激
名称:HolseLee
博客地址:www.cnblogs.com/cytus
个人邮箱:1073133650@qq.com
如需转载,请署名作者并附上原文链接,蒟蒻非常感激
名称:HolseLee
博客地址:www.cnblogs.com/cytus
个人邮箱:1073133650@qq.com