建图:源点—>边的起点(集合1中的)—>边的终点(集合2中的)—>汇点,所有边权均为1,
计算最大流,最后枚举起点的出边,边权为0的即为匹配上的,
可以这样理解:每条边表示起点和终点形成一组可选匹配,所以每个点只能被匹配1次(做起点和终点分别1次),所以可以看成是二分图匹配。
代码略丑:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cmath> 6 #include <ctime> 7 #include <algorithm> 8 #include <queue> 9 10 using namespace std; 11 12 template<const int _n> 13 struct Edge 14 { 15 struct Edge_base { int to,next,w; }e[_n]; 16 int cnt,p[_n]; 17 Edge() { clear(); } 18 int start(const int x) { return p[x]; } 19 void insert(const int x,const int y,const int z) 20 { e[++cnt].to=y; e[cnt].next=p[x]; e[cnt].w=z; p[x]=cnt; return ; } 21 Edge_base& operator[](const int x) { return e[x]; } 22 void clear() { cnt=1,memset(p,0,sizeof(p)); } 23 }; 24 25 int n,m,SSS,TTT,Ans; 26 int level[310],cur[310],Out[310],to[310],from[310]; 27 bool visited[310]; 28 Edge<15000> e; 29 30 bool Bfs(const int S) 31 { 32 int i,t; 33 queue<int> Q; 34 memset(level,0,sizeof(level)); 35 level[S]=1; 36 Q.push(S); 37 while(!Q.empty()) 38 { 39 t=Q.front();Q.pop(); 40 for(i=e.start(t);i;i=e[i].next) 41 { 42 if(!level[e[i].to] && e[i].w) 43 { 44 level[e[i].to]=level[t]+1; 45 Q.push(e[i].to); 46 } 47 } 48 } 49 return level[TTT]; 50 } 51 52 int Dfs(const int S,const int bk) 53 { 54 if(S==TTT)return bk; 55 int rest=bk; 56 for(int &i=cur[S];i;i=e[i].next) 57 { 58 if(level[e[i].to]==level[S]+1 && e[i].w) 59 { 60 int flow=Dfs(e[i].to,min(e[i].w,rest)); 61 e[i].w-=flow; 62 e[i^1].w+=flow; 63 if((rest-=flow)<=0)break; 64 } 65 } 66 if(bk==rest)level[S]=0; 67 return bk-rest; 68 } 69 70 int Dinic() 71 { 72 int flow=0; 73 while(Bfs(SSS)) 74 { 75 memcpy(cur,e.p,sizeof(int)*(n+n+3)); 76 flow+=Dfs(SSS,0x3f3f3f3f); 77 } 78 return flow; 79 } 80 81 82 83 int main() 84 { 85 freopen("path3.in","r",stdin); 86 freopen("path3.out","w",stdout); 87 int i,j,x,y; 88 89 scanf("%d%d",&n,&m); 90 for(i=1;i<=m;++i) 91 { 92 scanf("%d%d",&x,&y); 93 e.insert(x,y+n,1); 94 e.insert(y+n,x,0); 95 Out[x]++; 96 } 97 98 SSS=n+n+1,TTT=n+n+2; 99 for(i=1;i<=n;++i) 100 { 101 e.insert(SSS,i,1); 102 e.insert(i,SSS,0); 103 e.insert(i+n,TTT,1); 104 e.insert(TTT,i+n,0); 105 } 106 107 Dinic(); 108 109 for(i=e.start(SSS);i;i=e[i].next) 110 { 111 if(e[i].w)continue; 112 for(j=e.start(e[i].to);j;j=e[j].next) 113 { 114 if(e[j].to!=SSS && !e[j].w) 115 { 116 to[e[i].to]=e[j].to-n; 117 from[e[j].to-n]=e[i].to; 118 break; 119 } 120 } 121 } 122 123 for(i=1;i<=n;++i) 124 { 125 if(!from[i]) 126 { 127 int t=i; 128 while(t) 129 { 130 printf("%d ",t); 131 t=to[t]; 132 } 133 printf("\n"); 134 Ans++; 135 } 136 } 137 138 printf("%d\n",Ans); 139 140 return 0; 141 }
匈牙利写法详见:http://www.cnblogs.com/Ngshily/p/4988909.html