- 传送门 -
https://www.oj.swust.edu.cn/problem/show/1740
Description
假设有来自n 个不同单位的代表参加一次国际会议。每个单位的代表数分别为 ri,i=1,2,...,n 。会议餐厅共有m张餐桌,每张餐桌可容纳ci(i=1,2, ,m) 个代表就餐。 为了使代表们充分交流,希望从同一个单位来的代表不在同一个餐桌就餐。试设计一个算法, 给出满足要求的代表就餐方案。 编程任务: 对于给定的代表数和餐桌数以及餐桌容量,编程计算满足要求的代表就餐方案。
Input
由文件input.txt提供输入数据。文件第1行有2 个正整数m和n,m表示单位数,n表 示餐桌数,1<=m<=150, 1<=n<=270。文件第2 行有m个正整数,分别表示每个单位的代表 数。文件第3 行有n个正整数,分别表示每个餐桌的容量。
Output
程序运行结束时,将代表就餐方案输出到文件output.txt 中。如果问题有解,在文件第 1 行输出1,否则输出0。接下来的m行给出每个单位代表的就餐桌号。如果有多个满足要 求的方案,只要输出1 个方案。
4 5
4 5 3 5
3 5 2 6 4
1
1 2 4 5
1 2 3 4 5
2 4 5
1 2 3 4 5
Source
- 思路 -
终于打到容量不为 1 的网络流了!!!
开始转二分图多重匹配!!!
和前几题也差不多, 只是起点连向 x 集合(单位)的有向边的容量改为该单位代表数, y 集合(餐桌)连向终点的有向边的容量改为餐桌可容纳代表数, 两集合间的边容量还是都是 1 ,然后求最大流.
细节见代码.
- 代码 -
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int N = 500;
const int M = 1e5 + 5;
const int inf = 0x3f3f3f3f;
int R[N], C[N];
int CUR[N];
int TO[M], NXT[M], V[M];
int FRM[M], DIS[M], HD[N];
int tot, n, m, sz, cnt, ss, tt;
queue<int> q;
void add(int x, int y, int z) {
FRM[sz] = x; TO[sz] = y; V[sz] = z;
NXT[sz] = HD[x]; HD[x] = sz++;
FRM[sz] = y; TO[sz] = x; V[sz] = 0;
NXT[sz] = HD[y]; HD[y] = sz++;
}
bool bfs() {
memset(DIS, -1, sizeof (DIS));
q.push(ss);
DIS[ss] = 0;
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = HD[u]; i != -1; i = NXT[i]) {
int v = TO[i];
if (DIS[v] < 0 && V[i]) {
DIS[v] = DIS[u] + 1;
q.push(v);
}
}
}
return DIS[tt] > 0;
}
int dfs(int x, int a) {
if (x == tt) return a;
int flow = 0, f;
for (int& i = CUR[x]; i != -1; i = NXT[i]) {
if (V[i] && DIS[TO[i]] == DIS[x] + 1)
if (f = dfs(TO[i], min(a, V[i]))) {
V[i] -= f;
V[i^1] += f;
flow += f;
a -= f;
if (a == 0) break;
}
}
return flow;
}
int dinic() {
int flow = 0;
while (bfs()) {
memcpy(CUR, HD, sizeof (HD));
flow += dfs(ss, inf);
}
return flow;
}
void print() {
for (int i = 1; i <= n; ++i) {
for (int j = HD[i]; j != -1; j = NXT[j]) {
if (!V[j]) printf("%d ", TO[j] - n);
}
printf("
");
}
}
int main() {
memset(HD, -1, sizeof (HD));
scanf("%d%d", &n, &m);
ss = 0, tt = n + m + 1;
for (int i = 1; i <= n; ++i) {
scanf("%d", &C[i]);
add(ss, i, C[i]);
tot += C[i];
}
for (int i = 1; i <= m; ++i) {
scanf("%d", &R[i]);
add(n + i, tt, R[i]);
}
cnt = sz;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
add(i, n + j, 1);
if (dinic() == tot) {
printf("1
");
print();
}
else printf("0
");
return 0;
}