- 传送门 -
https://www.oj.swust.edu.cn/problem/show/1742
Time Limit: 10000 MS Memory Limit: 65536 KB
Total Submit: 294 Accepted: 140 Page View: 843
Description
假设一个试题库中有n道试题。每道试题都标明了所属类别。同一道题可能有多个类别 属性。现要从题库中抽取m 道题组成试卷。并要求试卷包含指定类型的试题。试设计一个 满足要求的组卷算法。 编程任务: 对于给定的组卷要求,计算满足要求的组卷方案。
Input
由文件input.txt提供输入数据。文件第1行有2个正整数k和n (2 <=k<= 20, k<=n<= 1000) k 表示题库中试题类型总数,n 表示题库中试题总数。第2 行有k 个正整数,第i 个正整数 表示要选出的类型i 的题数。这k个数相加就是要选出的总题数m。接下来的n行给出了题 库中每个试题的类型信息。每行的第1 个正整数p表明该题可以属于p类,接着的p个数是 该题所属的类型号。
Output
程序运行结束时,将组卷方案输出到文件output.txt 中。文件第i 行输出 “i:”后接类 型i的题号。如果有多个满足要求的方案,只要输出1 个方案。如果问题无解,则输出“No Solution!”。
3 15
3 3 4 2
1 2
1 3
1 3
1 3
1 3
3 1 2 3
2 2 3
2 1 3
1 2
1 2
2 1 2
2 1 3
2 1 2
1 1
3 1 2 3
1: 1 6 8
2: 7 9 10
3: 2 3 4 5
Source
- 思路 -
起点 -> 试题类型 (试题数量)
试题类型 -> 试题 (1)
试题 -> 终点 (1)
简单的建模...
求最大流...
细节见代码.
- 代码 -
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 1100;
const int M = 1e5;
const int inf = 0x3f3f3f3f;
queue<int> q;
int NXT[M], V[M], TO[M], FRM[M];
int HD[N], CUR[N], DIS[N];
int n, m, ss, tt, sz, cnt, tot, ans;
bool bfs() {
memset(DIS, -1, sizeof (DIS));
DIS[ss] = 0;
q.push(ss);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = HD[u]; i != -1; i = NXT[i]) {
if (V[i] && DIS[TO[i]] < 0) {
DIS[TO[i]] = DIS[u] + 1;
q.push(TO[i]);
}
}
}
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) {
printf("%d:", i);
for (int j = HD[i]; j != -1; j = NXT[j]) {
if (V[j] == 0 && TO[j] != ss) printf(" %d", TO[j] - n);
//开始没注意细节wa了一发
}
printf("
");
}
}
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++;
}
int main () {
memset(HD, -1, sizeof (HD));
scanf("%d%d", &n, &m);
ss = 0, tt = n + m + 1;
for (int i = 1, x; i <= n; ++i) {
scanf("%d", &x);
add(ss, i, x);
tot += x;
}
for (int i = 1, x, a; i <= m; ++i) {
scanf("%d", &x);
while (x--) {
scanf("%d", &a);
add(a, i + n, 1);
}
add(i + n, tt, 1);
}
if (tot != dinic())
printf("No Solution!
");
else
print();
return 0;
}