zoukankan      html  css  js  c++  java
  • [cogs729]圆桌问题(最大流)

    传送门

    模型

    二分图多重匹配问题,可以用最大流解决。

    实现

    建立二分图,每个单位为X集合中的顶点,每个餐桌为Y集合中的顶点,增设附加源S和汇T。

    1、从S向每个Xi顶点连接一条容量为该单位人数的有向边。

    2、从每个Yi顶点向T连接一条容量为该餐桌容量的有向边。

    3、X集合中每个顶点向Y集合中每个顶点连接一条容量为1的有向边。

    求网络最大流,如果最大流量等于所有单位人数之和,则存在解,否则无解。对于每个单位,从X集合对应点出发的所有满流边指向的Y集合的顶点就是该单位人员的安排情况(一个可行解)。

    分析

    对于一个二分图,每个顶点可以有多个匹配顶点,称这类问题为二分图多重匹配问题。X,Y集合之间的边容量全部是1,保证两个点只能匹配一次(一个餐桌上只能有一个单位的一个人),源

    汇的连边限制了每个点匹配的个数。求出网络最大流,如果流量等于X集合所有点与S边容量之和,那么则说明X集合每个点都有完备的多重匹配。

    注意 cogs 需要写文件!

    ——代码

      1 #include <queue>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <iostream>
      5 #define N 50001
      6 #define M 5000001
      7 #define min(x, y) ((x) < (y) ? (x) : (y))
      8 
      9 int n, m, cnt, sum, ans, s, t;
     10 int head[N], to[M], val[M], next[M], dis[N], cur[N];
     11 
     12 inline int read()
     13 {
     14     int x = 0, f = 1;
     15     char ch = getchar();
     16     for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
     17     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
     18     return x * f;
     19 }
     20 
     21 inline void add(int x, int y, int z)
     22 {
     23     to[cnt] = y;
     24     val[cnt] = z;
     25     next[cnt] = head[x];
     26     head[x] = cnt++;
     27 }
     28 
     29 inline bool bfs()
     30 {
     31     int i, u, v;
     32     std::queue <int> q;
     33     memset(dis, -1, sizeof(dis));
     34     q.push(s);
     35     dis[s] = 0;
     36     while(!q.empty())
     37     {
     38         u = q.front(), q.pop();
     39         for(i = head[u]; i ^ -1; i = next[i])
     40         {
     41             v = to[i];
     42             if(val[i] && dis[v] == -1)
     43             {
     44                 dis[v] = dis[u] + 1;
     45                 if(v == t) return 1;
     46                 q.push(v);
     47             }
     48         }
     49     }
     50     return 0;
     51 }
     52 
     53 inline int dfs(int u, int maxflow)
     54 {
     55     if(u == t) return maxflow;
     56     int v, d, ret = 0;
     57     for(int &i = cur[u]; i ^ -1; i = next[i])
     58     {
     59         v = to[i];
     60         if(val[i] && dis[v] == dis[u] + 1)
     61         {
     62             d = dfs(v, min(val[i], maxflow - ret));
     63             ret += d;
     64             val[i] -= d;
     65             val[i ^ 1] += d;
     66             if(ret == maxflow) return ret;
     67         }
     68     }
     69     return ret;
     70 }
     71 
     72 int main()
     73 {
     74     freopen("roundtable.in","r",stdin);
     75     freopen("roundtable.out","w",stdout);
     76     int i, j, x;
     77     m = read();
     78     n = read();
     79     s = 0, t = n + m + 1;
     80     memset(head, -1, sizeof(head));
     81     for(i = 1; i <= m; i++)
     82     {
     83         sum += x = read();
     84         add(s, i, x), add(i, s, 0);
     85         for(j = 1; j <= n; j++)
     86             add(i, j + m, 1), add(j + m, i, 0);
     87     }
     88     for(i = 1; i <= n; i++)
     89     {
     90         x = read();
     91         add(i + m, t, x), add(t, i + m, 0);
     92     }
     93     while(bfs())
     94     {
     95         for(i = s; i <= t; i++) cur[i] = head[i];
     96         ans += dfs(s, 1e9);
     97     }
     98     if(ans ^ sum)
     99     {
    100         puts("0");
    101         return 0;
    102     }
    103     puts("1");
    104     for(i = 1; i <= m; puts(""), i++)
    105         for(j = head[i]; j ^ -1; j = next[j])
    106             if(!val[j])
    107                 printf("%d ", to[j] - m); 
    108     return 0;
    109 }
    View Code
  • 相关阅读:
    RMAN备份脚本
    配置putty隧道登录远程window远程或远程数据库
    ssh登录报错:no common kex alg
    Solaris上修改进程能够打开的最大文件句柄数
    如何在V890上安装配置rsc(转)
    Oracle表或分区导出脚本
    检查日期合法性脚本(转)
    Solaris下常用的磁带操作命令
    如何从solaris操作系统上获取机器的sn号
    如何修复failed磁盘和"DISABLED RECOVER"状态的plex
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/6938508.html
Copyright © 2011-2022 走看看