1. 程式人生 > >【網絡流24題】圓桌聚餐

【網絡流24題】圓桌聚餐

string urn 若有 down 餐廳 最大 交流 block cstring

LOJ 6004 【網絡流24題】圓桌聚餐

題面

假設有來自\(n\)個不同單位的代表參加一次國際會議。每個單位的代表數分別為\(r_i\)。會議餐廳共有\(m\)張餐桌,每張餐桌可容納\(c_i\)個代表就餐。
為了使代表們充分交流,希望從同一個單位來的代表不在同一個餐桌就餐。
試設計一個算法,給出滿足要求的代表就餐方案。

題解

  1. 源點向每個單位連一條邊,邊權是該單位人數;
  2. 每個單位向各個餐桌連一條邊,邊權是1;
  3. 每個餐桌向匯點連一條邊,邊權是餐桌容納人數。

如果最大流 < 總人數,則無解。若有解,根據單位和餐桌之間哪些邊跑滿了來輸出具體方案即可。

我犯過的錯誤:源點匯點的編號標錯了……

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
#define space putchar(' ')
#define enter putchar('\n')
template <class T>
bool read(T &x){
    char c;
    bool op = 0;
    while(c = getchar(), c < '0'
|| c > '9') if(c == '-') op = 1; else if(c == EOF) return 0; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; return 1; } template <class T> void write(T x){ if
(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } const int N = 4005, M = 2000005, INF = 0x3f3f3f3f; int ncnt, n, m, s, t, ans, sum; int ecnt = 1, adj[N], nxt[M], go[M], cap[M], cur[N]; int que[N], qr, lev[N], stk[N], top; void ADD(int u, int v, int w){ go[++ecnt] = v; nxt[ecnt] = adj[u]; adj[u] = ecnt; cap[ecnt] = w; } void add(int u, int v, int w){ ADD(u, v, w), ADD(v, u, 0); } bool bfs(){ for(int i = 1; i <= ncnt; i++) lev[i] = -1, cur[i] = adj[i]; lev[s] = 0, que[qr = 1] = s; for(int ql = 1; ql <= qr; ql++){ int u = que[ql]; for(int e = adj[u], v; e; e = nxt[e]) if(cap[e] && lev[v = go[e]] == -1){ lev[v] = lev[u] + 1, que[++qr] = v; if(v == t) return 1; } } return 0; } int dinic(int u, int flow){ if(u == t) return flow; int delta, ret = 0; for(int &e = cur[u], v; e; e = nxt[e]) if(cap[e] && lev[v = go[e]] > lev[u]){ delta = dinic(v, min(cap[e], flow - ret)); if(delta){ cap[e] -= delta; cap[e ^ 1] += delta; ret += delta; if(ret == flow) return flow; } } lev[u] = -1; return ret; } int main(){ read(m), read(n); ncnt = n + m + 2, s = ncnt - 1, t = ncnt; for(int i = 1, val; i <= m; i++) read(val), add(s, i, val), sum += val; for(int i = 1, val; i <= n; i++) read(val), add(i + m, t, val); for(int i = 1; i <= m; i++) for(int j = 1; j <= n; j++) add(i, j + m, 1); while(bfs()) ans += dinic(s, INF); if(ans < sum){ puts("0"); return 0; } puts("1"); for(int u = 1; u <= m; u++){ for(int e = adj[u]; e; e = nxt[e]) if(!(e & 1) && !cap[e]) write(go[e] - m), space; enter; } return 0; }

【網絡流24題】圓桌聚餐