题目描述
«问题描述:
假设一个试题库中有n道试题。每道试题都标明了所属类别。同一道题可能有多个类别属性。现要从题库中抽取m 道题组成试卷。并要求试卷包含指定类型的试题。试设计一个满足要求的组卷算法。
«编程任务:
对于给定的组卷要求,计算满足要求的组卷方案。
输入输出格式
输入格式:
第1行有2个正整数k和n (2 <=k<= 20, k<=n<= 1000)
k 表示题库中试题类型总数,n 表示题库中试题总数。第2 行有k 个正整数,第i 个正整数表示要选出的类型i的题数。这k个数相加就是要选出的总题数m。接下来的n行给出了题库中每个试题的类型信息。每行的第1 个正整数p表明该题可以属于p类,接着的p个数是该题所属的类型号。
输出格式:
第i 行输出 “i:”后接类型i的题号。如果有多个满足要求的方案,只要输出1个方案。如果问题无解,则输出“No Solution!”。
输入输出样例
输入样例#1: 复制
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: 1 6 8 2: 7 9 10 3: 2 3 4 5
说明
感谢 @PhoenixEclipse 提供spj
这个题目和圆桌问题是一样的,所以题解可以看圆桌问题,然后再自己写一下这个
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <queue> #include <cmath> #include <iostream> #include <vector> #define inf 0x3f3f3f3f using namespace std; const int maxn = 1e5 + 10; int s, t, n, m; struct node { int from, to, cap, flow; node(int from=0,int to=0,int cap=0,int flow=0):from(from),to(to),cap(cap),flow(flow){} }; vector<node>e; vector<int>G[maxn]; int level[maxn], iter[maxn], head[maxn]; void add(int u,int v,int c) { e.push_back(node(u, v, c, 0)); e.push_back(node(v, u, 0, 0)); int len = e.size(); G[u].push_back(len - 2); G[v].push_back(len - 1); } void bfs(int s) { memset(level, -1, sizeof(level)); queue<int>que; que.push(s); level[s] = 0; while(!que.empty()) { int u = que.front(); que.pop(); for(int i=0;i<G[u].size();i++) { node &now = e[G[u][i]]; if(level[now.to]<0&&now.cap>now.flow) { level[now.to] = level[u] + 1; que.push(now.to); } } } } int dfs(int u,int v,int f) { if (u == v) return f; for(int &i=iter[u];i<G[u].size();i++) { node &now = e[G[u][i]]; if(now.cap>now.flow&&level[now.to]>level[u]) { int d = dfs(now.to, v, min(f, now.cap - now.flow)); if(d>0) { now.flow += d; e[G[u][i] ^ 1].flow -= d; return d; } } } return 0; } int sum = 0; bool dinic() { int flow = 0; while(1) { bfs(s); if (level[t] < 0) return flow==sum; memset(iter, 0, sizeof(iter)); int f; while ((f = dfs(s, t, inf)) > 0) flow += f; } } int main() { cin >> m >> n; s = 0, t = n + m + 1; for (int i = 1; i <= m; i++) { int x; cin >> x; add(s, i, x); sum += x; } for (int i = 1; i <= n; i++) add(i + m, t, 1); for (int i = 1; i <= n; i++) { int p; cin >> p; while(p--) { int q; cin >> q; add(q, i, 1); } } int ans = dinic(); if (ans == 0) printf("No Solution! "); else { for(int i=1;i<=m;i++) { printf("%d:", i); for(int j=0;j<G[i].size();j++) { if(e[G[i][j]^1].flow==-1) { printf(" %d", e[G[i][j]].to); } } printf(" "); } } return 0; }