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 }

 

你可能感兴趣的:(poj)