【網路流24題】 5. 圓桌問題 題解
阿新 • • 發佈:2020-09-06
題意
有來自\(m\)個不同單位的代表參加一次國際會議。第\(i\)個單位派出了\(r_i\)個代表。
會議的餐廳共有\(n\)張餐桌,第\(i\)張餐桌可容納\(c_i\)個代表就餐。
為了使代表們充分交流,希望從同一個單位來的代表不在同一個餐桌就餐。請給出一個滿足要求的代表就餐方案。
思路
我們考慮從源點向每個單位連線一條容量為該單位人數的邊,從每個桌子向匯點連線一條容量為該桌子人數的邊,然後每個單位向每個桌子都連線一條容量為\(1\)的邊(因為每張桌子上每個單位最多隻能有一個人),然後跑最大流。如果最大流和總人數相同,則有解,否則無解。
程式碼
PS:Dinic寫的太慢(dfs)會被卡QAQ
/** * luogu P3254 https://www.luogu.com.cn/problem/P3254 * Dinic **/ #include <cstdio> #include <cstring> #include <algorithm> #include <queue> using namespace std; const int maxn = 1000; const int S = 0; const int T = maxn - 1; const int INF = 0x5f5f5f5f; struct Edge { int to, val, nxt; }e[maxn * maxn]; int numedge, head[maxn], n, m, depth[maxn], ans, sum; inline void AddEdge(int from, int to, int val) { e[numedge].to = to; e[numedge].val = val; e[numedge].nxt = head[from]; head[from] = numedge; numedge++; } inline void init() { memset(head, -1, sizeof(head)); } inline bool bfs() { memset(depth, 0, sizeof(depth)); depth[S] = 1; queue<int> q; q.push(S); while (!q.empty()) { int u = q.front(); q.pop(); for (int i = head[u]; ~i; i = e[i].nxt) { int to = e[i].to; if (!depth[to] && e[i].val > 0) { depth[to] = depth[u] + 1; q.push(to); } } } return depth[T] != 0; } int dfs(int u, int flow) { if (u == T || !flow) return flow; int sum = 0; for (int i = head[u]; ~i; i = e[i].nxt) { int to = e[i].to; if (depth[to] > depth[u] && e[i].val > 0) { int di = dfs(to, min(flow, e[i].val)); if (di > 0) { sum += di; flow -= di; e[i].val -= di; e[i ^ 1].val += di; // return di; } } } if (!sum) depth[u] = 0; return sum; } inline int Dinic() { int res = 0; while (bfs()) { int d; while ((d = dfs(S, INF))) res += d; } return res; } int main() { init(); scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { int x; scanf("%d", &x); sum += x; AddEdge(S, i, x); AddEdge(i, S, 0); } for (int i = 1; i <= m; i++) { int x; scanf("%d", &x); AddEdge(i + n, T, x); AddEdge(T, i + n, 0); } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { AddEdge(i, j + n, 1); AddEdge(j + n, i, 0); } } ans = Dinic(); if (ans == sum) { printf("1\n"); for (int i = 1; i <= n; i++) { for (int j = head[i]; ~j; j = e[j].nxt) { int to = e[j].to; if (to > n && e[j].val == 0) { printf("%d ", to - n); } } putchar('\n'); } } else { printf("0\n"); } return 0; }