试题库
题面: 假设一个试题库中有 n道试题。每道试题都标明了所属类别。同一道题可能有多个类别属性。现要从题库中抽取m道题组成试卷。并要求试卷包含指定类型的试题。试设计一个满足要求的组卷算法。
思路: 建模,跑一遍最大流即可
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
using namespace std;
const int N = 10005;
int n, m, ss, tt, k;
int dis[N];
int cur[N];
bool vis[N];
queue<int> q;
struct Edge {
int to;
int value;
int next;
} e[N * 10];
int head[N], cnt = -1;
void add(int from, int to, int value) {
cnt++;
e[cnt].to = to;
e[cnt].value = value;
e[cnt].next = head[from];
head[from] = cnt;
}
bool bfs(int s, int t) {
q = queue<int>();
memset(dis, -1, sizeof(dis));
dis[s] = 0;
q.push(s);
while (!q.empty()) {
int x = q.front();
q.pop();
for (int i = head[x]; i > -1; i = e[i].next) {
int now = e[i].to;
if (dis[now] == -1 && e[i].value != 0) {
dis[now] = dis[x] + 1;
q.push(now);
}
}
}
return dis[t] != -1;
}
int dfs(int x, int t, int maxflow) {
if (x == t)
return maxflow;
int ans = 0;
for (int i = cur[x]; i > -1; i = e[i].next) {
int now = e[i].to;
if (dis[now] != dis[x] + 1 || e[i].value == 0 || ans >= maxflow)
continue;
cur[x] = i;
int f = dfs(now, t, min(e[i].value, maxflow - ans));
e[i].value -= f;
e[i ^ 1].value += f;
ans += f;
}
return ans;
}
int Dinic(int s, int t) {
int ans = 0;
while (bfs(s, t)) {
memcpy(cur, head, sizeof(head));
ans += dfs(s, t, INF);
}
return ans;
}
int main() {
memset(head, -1, sizeof(head));
scanf("%d%d", &k,&n);
ss=0,tt=n+k+1;
int sum=0;
for(int i=1;i<=k;i++)
{
int x;
scanf("%d",&x);
sum+=x;
add(n+i,tt,x);
add(tt,n+i,0);
}
for(int i=1;i<=n;i++)
{
add(ss,i,1);
add(i,ss,0);
}
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
for(int j=1;j<=x;j++)
{
int tmp;
scanf("%d",&tmp);
add(i,tmp+n,1);
add(tmp+n,i,0);
}
}
int ans=Dinic(ss,tt);
if(sum!=ans)
{
puts("No Solution!");
return 0;
}
for(int i=n+1;i<=n+k;i++)
{
printf("%d:",i-n);
for(int j=head[i];j!=-1;j=e[j].next)
{
if(e[j].to!=tt&&e[j].value==1)
{
printf(" %d",e[j].to);
}
}
puts("");
}
return 0;
}