POJ 1698 (二分图的多重匹配)
转载:http://www.cppblog.com/MatoNo1/archive/2011/03/26/142766.aspx
我们知道在一个图中,每个点最多只能匹配一条边的情况,是二分图的最大匹配问题.然而还有种情况是:每个点可以匹配多条边,但有上限,假设为L.即Li表示最多点i可以和Li条边相关联.
二分图多重最大匹配:
1.建立一个源点S和汇点T.
2.S指向x顶点,容量为x内点的L值.y顶点指向T,容量为y内点的L值.
3.原图中的各边在新图中仍存在,容量为1.
那么S到T的最大流就是多重最大匹配.
例如POJ1698:
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #define _clr(x, y) memset(x, y, sizeof(x)) 5 #define Min(x, y) (x < y ? x : y) 6 #define Max(x, y) (x > y ? x : y) 7 #define INF 0x3f3f3f3f 8 #define N 400 9 using namespace std; 10 11 int edge[N][N], dist[N]; 12 int T, S, Sum, n; 13 bool used[N]; 14 15 bool bfs() 16 { 17 _clr(dist, -1); 18 queue<int> Q; 19 dist[S] = 0; 20 Q.push(S); 21 while(!Q.empty()) 22 { 23 int u = Q.front(); 24 Q.pop(); 25 for(int v=0; v<=T; v++) 26 { 27 if(edge[u][v] && dist[v]<0) 28 { 29 dist[v] = dist[u] + 1; 30 Q.push(v); 31 } 32 } 33 } 34 return dist[T]>0? 1 : 0; 35 } 36 37 int dfs(int u, int alpha) 38 { 39 int a; 40 if(u==T) return alpha; 41 for(int i=0; i<=T; i++) 42 { 43 if(edge[u][i] && dist[i]==dist[u]+1 && (a=dfs(i, Min(alpha, edge[u][i])))) 44 { 45 edge[u][i] -= a; 46 edge[i][u] += a; 47 return a; 48 } 49 } 50 dist[u] = -1; 51 return 0; 52 } 53 void Dinic() 54 { 55 int ans=0, a=0; 56 while(bfs()) 57 while(a=dfs(0, INF)) ans += a; 58 printf ("%s\n", ans==Sum ? "Yes" : "No"); 59 } 60 61 int main() 62 { 63 int K, week[10]; 64 scanf("%d", &K); 65 while(K--) 66 { 67 int day = 0, d, w; 68 scanf("%d", &n); 69 Sum = 0, S=0; 70 _clr(week, 0); 71 _clr(edge, 0); 72 for(int i=1; i<=n; i++) // 1--n之间表示电影,n+1---T之间表示天数! 73 { 74 for(int i1=0; i1<7; i1++) scanf("%d", week+i1); 75 scanf("%d%d", &d, &w); 76 day = Max(day, w); 77 edge[S][i] = d; // 源点向每个电影节点 x 连接一条权值为拍摄此电影所需天数的值. 78 Sum += d; 79 80 for(int j=0; j<w; j++) // W周之内完成. 81 { 82 for(int k=0; k<7; k++) 83 if(week[k]) 84 edge[i][n+j*7+k+1] = 1; //第i部电影可以在w周内的周k拍摄. 85 } 86 T = day*7+n+1; 87 for(int i=n+1; i<T; i++) 88 edge[i][T] = 1; 89 } 90 Dinic(); 91 } 92 return 0; 93 }