NK 飞行员配对方案问题 网络流
http://acm.nankai.edu.cn/p2121.html
南开的24道网络流里的第一个 汉语题目 哈哈
二分匹配,增加一个源点S 一个汇点T 然后按最大流算 dinic
下面用矩阵和链表加边做的,两种写法目前当模板了
(一)用矩阵存储 运行时间 0MS
代码:
#include<iostream> #include<cstdio> #include<string> #include<queue> #include<cstring> #define Min(a,b)a<b?a:b #define inf 100000 using namespace std; int map[102][102],level[102]; int m,n,SUM,mark; int dfs(int x,int Cap) { if(x==n+1) return Cap; int i,temp,tt,y=0; for(i=1;i<=n+1;i++) { if(level[i]==level[x]+1&&Cap>y&&map[x][i]>0) { temp=Min(Cap-y,map[x][i]); if(temp==0)continue; tt=dfs(i,temp); map[x][i]-=tt; map[i][x]+=tt; y+=tt; } } return y; } int bfs() { int tt,k; queue<int>qu; memset(level,-1,sizeof(level)); level[0]=0; qu.push(0); while(!qu.empty()) { tt=qu.front(); qu.pop(); for(k=1;k<=n+1;k++) if(map[tt][k]>0&&level[k]==-1) { level[k]=level[tt]+1; qu.push(k); } } if(level[n+1]!=-1)return 1; else return 0; } void dinic() { SUM=0; mark=0; while(bfs()) { SUM+=dfs(0,inf); } return ; } void print() { if(SUM==0) { printf("No Solution!\n"); return ; } int i,j; printf("%d\n",SUM); for(i=0;i<=m;i++)//这方法开始没想到,看的别人的 还是对网络流了解不深 for(j=m+1;j<=n+1;j++) if(map[i][j]==0&&i!=0&&j!=n+1) printf("%d %d\n",i,j); return ; } int main() { while(~scanf("%d%d",&m,&n)) { int i,j; memset(map,-1,sizeof(map)); for(i=1;i<=m;i++) { map[0][i]=1; map[i][0]=0; } for(i=m+1;i<=n;i++) { map[i][n+1]=1; map[n+1][i]=0; } while(~scanf("%d%d",&i,&j)) { if(i==-1&&j==-1)break; map[i][j]=1; map[j][i]=0; } dinic(); print(); } return 0; }
(二)链表,加边
代码:
#include<iostream> #include<cstdio> #include<string> #include<queue> #include<cstring> #define Min(a,b)a<b?a:b #define inf 1000 using namespace std; int level[102],head[102]; int m,n,s_edge,SUM; struct Edge { int from,to,w,next; }edge[12002]; void addedge(int u,int v, int ww ) { s_edge++; edge[s_edge].from=u; edge[s_edge].to=v; edge[s_edge].w=ww; edge[s_edge].next=head[u]; head[u]=s_edge; s_edge++; edge[s_edge].from=v; edge[s_edge].to=u; edge[s_edge].w=0; edge[s_edge].next=head[v]; head[v]=s_edge; } int dfs(int x,int Cap) { if(x==n+1)return Cap; int y=0,t,temp,To; for(t=head[x];t!=-1;t=edge[t].next) { To=edge[t].to; if(level[To]==level[x]+1&&edge[t].w>0&&Cap-y>0) { temp=Min(Cap-y,edge[t].w); int tt=dfs(To,temp); edge[t].w-=tt; edge[t^1].w+=tt; y+=tt; } } return y; } int bfs() { int t,To,tt; queue<int>qu; memset(level,-1,sizeof(level)); level[0]=0; qu.push(0); while(!qu.empty()) { tt=qu.front(); qu.pop(); for(t=head[tt];t!=-1;t=edge[t].next) { To=edge[t].to; if(level[To]==-1&&edge[t].w>0) { level[To]=level[tt]+1; qu.push(To); } } } if(level[n+1]!=-1)return 1; else return 0 ; } void dinic() { SUM=0; while(bfs()) { SUM+=dfs(0,inf); } return ; } void print() { if(SUM==0) { printf("No Solution!\n"); return ; } int i,j; printf("%d\n",SUM); for(i=0;i<=s_edge;i+=2) if(edge[i].w==0&&edge[i].from!=0&&edge[i].to!=n+1) printf("%d %d\n",edge[i].from,edge[i].to); return ; } int main() { while(~scanf("%d%d",&m,&n)) { int i,j; s_edge=-1; memset(head,-1,sizeof(head)); //memset(head,0,sizeof(head));错误,特别注意!!! for(i=1;i<=m;i++) addedge(0,i,1);//源点是0 for(i=m+1;i<=n;i++) addedge(i,n+1,1);//n+1是汇点 while(~scanf("%d%d",&i,&j)) { if(i==-1&&j==-1)break; addedge(i,j,1); } dinic(); print(); } return 0; }