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 }

 

posted @ 2015-02-22 01:24  无道圣君  阅读(313)  评论(0编辑  收藏  举报