[题解] PowerOJ 1742 试题库问题 (最大流)

- 传送门 -

 https://www.oj.swust.edu.cn/problem/show/1742

#  1742: 试题库问题 SPJ

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

线性规划与网络流24题

 

- 思路 -

 起点 -> 试题类型 (试题数量)
 试题类型 -> 试题 (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;
}
原文地址:https://www.cnblogs.com/Anding-16/p/7418824.html