網路流24題 P3254 圓桌問題 (二分圖多重匹配轉最大流)
阿新 • • 發佈:2018-12-13
假設有來自m 個不同單位的代表參加一次國際會議。每個單位的代表數分別為ri (i =1,2,……,m)。
會議餐廳共有n 張餐桌,每張餐桌可容納ci (i =1,2,……,n)個代表就餐。
為了使代表們充分交流,希望從同一個單位來的代表不在同一個餐桌就餐。試設計一個演算法,給出滿足要求的代表就餐方案。
對於給定的代表數和餐桌數以及餐桌容量,程式設計計算滿足要求的代表就餐方案。
輸入輸出格式
輸入格式:
第1 行有2 個正整數m 和n,m 表示單位數,n 表示餐桌數,1<=m<=150, 1<=n<=270。
第2 行有m 個正整數,分別表示每個單位的代表數。
第3 行有n 個正整數,分別表示每個餐桌的容量。
輸出格式:
如果問題有解,第1 行輸出1,否則輸出0。接下來的m 行給出每個單位代表的就餐桌號。如果有多個滿足要求的方案,只要輸出1 個方案。
輸入輸出樣例
輸入樣例#1: 複製
4 5 4 5 3 5 3 5 2 6 4輸出樣例#1: 複製
1 1 2 4 5 1 2 3 4 5 2 4 5 1 2 3 4 5源點向單位Xi連容量為該單位人數的線,Yi向匯點連餐桌容量的線。 每個Xi向每個Yi連容量為1的線 求最大流,若最大流等於單位人數之和,則有解
#pragma GCC optimize(2) #include<stdio.h> #include<algorithm> #include<string.h> #include<queue> using namespace std; const int maxn = 1e5; const int inf = 0x3f3f3f3f; typedef long long ll; int head[maxn], level[maxn], r[maxn], c[maxn]; int n, m, tot; struct node { int v, w, next; }edge[maxn]; void addedge(int u, int v, int w) { edge[tot].v = v; edge[tot].w = w; edge[tot].next = head[u]; head[u] = tot++; edge[tot].v = u; edge[tot].w = 0; edge[tot].next = head[v]; head[v] = tot++; return; } bool bfs(int s, int t) { queue<int>q; memset(level, 0, sizeof(level)); level[s] = 1; q.push(s); while (!q.empty()) { int u = q.front(); q.pop(); for (int i = head[u]; i != -1; i = edge[i].next) { int v = edge[i].v; if (level[v] == 0 && edge[i].w) { level[v] = level[u] + 1; q.push(v); } } } return level[t] != 0; } int dfs(int s, int t, int f) { if (s == t) { return f; } int cost = 0; for (int i = head[s]; i != -1; i = edge[i].next) { int v = edge[i].v; int w = edge[i].w; if (level[v] == level[s] + 1 && w) { int d = dfs(v, t, min((f - cost), w)); if (d > 0) { edge[i].w -= d; edge[i^1].w += d; cost += d; if (cost == f) { break; } } else { level[v] = 0; } } } return cost; } int dinic(int s, int t) { int flow = 0; while (bfs(s, t)) { flow += dfs(s, t, inf); } return flow; } int main() { //freopen("C://input.txt", "r", stdin); scanf("%d%d", &m, &n); memset(head, -1, sizeof(head)); int sum = 0; int s = 0, t = m + n + 1; for (int i = 1; i <= m; i++) { scanf("%d", &r[i]); addedge(s, i, r[i]); sum += r[i]; } for (int i = 1; i <= n; i++) { scanf("%d", &c[i]); addedge(i + m, t, c[i]); } for (int i = 1; i <= m; i++) { for (int j = m + 1; j <= n + m; j++) { addedge(i, j, 1); } } if (sum == dinic(s, t)) { printf("1\n"); for (int i = 1; i <= m; i++) { for (int j = head[i]; j != -1; j = edge[j].next) { if (edge[j ^ 1].w) { printf("%d ", edge[j].v - m); } } printf("\n"); } } else { printf("0\n"); } return 0; }