zoukankan      html  css  js  c++  java
  • 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
    ", 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 }
  • 相关阅读:
    JAVA中toString方法
    编辑器未包含main类型解决方法
    Ubuntu中设置环境变量详解
    vim中执行shell命令小结
    vim使用手册
    vim命令总结
    如何修改远程桌面连接3389端口
    Linux磁盘与文件系统管理
    文件与文件系统的压缩与打包命令
    Mininet VM设置笔记
  • 原文地址:https://www.cnblogs.com/khan724/p/4297288.html
Copyright © 2011-2022 走看看