假设一个试题库中有n道试题。每道试题都标明了所属类别。同一道题可能有多个类别
属性。现要从题库中抽取m 道题组成试卷。并要求试卷包含指定类型的试题。试设计一个
满足要求的组卷算法。
编程任务:
对于给定的组卷要求,计算满足要求的组卷方案。
数据输入:
由文件input.txt提供输入数据。文件第1行有2个正整数n和k (2 <=k<= 20, k<=n<= 1000)
k 表示题库中试题类型总数,n 表示题库中试题总数。第2 行有k 个正整数,第i 个正整数
表示要选出的类型i 的题数。这k个数相加就是要选出的总题数m。接下来的n行给出了题
库中每个试题的类型信息。每行的第1 个正整数p表明该题可以属于p类,接着的p个数是
该题所属的类型号。
结果输出:
程序运行结束时,将组卷方案输出到文件output.txt 中。文件第i 行输出 “i:”后接类
型i的题号。如果有多个满足要求的方案,只要输出1 个方案。如果问题无解,则输出“No
Solution!”。
输入示例: 输出示例:
3 15 1: 1 6 8
3 3 4 2: 7 9 10
2 1 2 3: 2 3 4 5
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
分析:
这题有点水,二分图多重匹配。所有题目为X点,所有类型为Y点,建立源点S,汇点T
S连接所有的X点,容量为1,表示每题只能选择一次。所有的Y点连接T点,容量为每个类型的需求题数。
对于每题X能属于不同的Y的类型,就连接对应的X,Y点,容量为1,其实这里的容量1还是无穷都无所谓的,因为源汇点已经限制了容量。
然后求一次最大流,如果最大流等于题目合,就有解。对于所有从X出发指向Y的边,流量为1则为一个可行解。否则无解输出No Solution!。
代码应该也没什么要解释的。
代码:
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
using namespace std;
const int maxn = 1001;
const int INF = 1<<30;
struct edge{
int from,to,cap,flow;
edge(int a,int b,int c,int d):from(a),to(b),cap(c),flow(d)
{}
};
vector<int> g[maxn];
vector<edge> edges;
bool visit[maxn];
int d[maxn];
int cur[maxn];
int s,t;
void addedge(int from,int to,int cap)
{
edges.push_back(edge(from,to,cap,0));
edges.push_back(edge(to,from,0,0));
int m=edges.size();
g[from].push_back(m-2);
g[to].push_back(m-1);
}
bool BFS()
{
memset(visit,false,sizeof(visit));
d[s]=0;
queue<int> q;
q.push(s);
visit[s]=true;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0;i<g[x].size();i++){
edge &e=edges[g[x][i]];
if(!visit[e.to]&&e.cap>e.flow){
visit[e.to]=true;
d[e.to]=d[x]+1;
q.push(e.to);
}
}
}
return visit[t];
}
int DFS(int x,int a)
{
if(x==t||a==0) return a;
int flow=0,f;
for(int &i=cur[x];i<g[x].size();i++){
edge &e=edges[g[x][i]];
if(d[e.to]==d[x]+1&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0){
flow+=f;
a-=f;
e.flow+=f;
edges[g[x][i]^1].flow-=f;
if(a==0) break;
}
}
return flow;
}
int main()
{
int k,n;
scanf("%d%d",&k,&n);
s=0;t=k+n+1;
int cap,sum=0;
for(int i=1;i<=k;i++){
scanf("%d",&cap);
sum+=cap;
addedge(i,t,cap);
}
getchar();
for(int i=k+1;i<=k+n;i++){
int res=0,c;
while((c=getchar())!='\n'){
if(c==' ') {addedge(i,res,1);res=0;}
else res=res*10+c-'0';
}
addedge(i,res,1);
addedge(s,i,1);
}
int flow=0;
while(BFS()){
memset(cur,0,sizeof(cur));
flow+=DFS(s,INF);
}
if(flow!=sum) printf("“No Solution!\n");
else{
for(int i=1;i<=k;i++){
printf("%d:",i);
for(int j=0;j<g[i].size();j++){
edge &e=edges[g[i][j]^1];
if(e.flow==1) printf(" %d",e.from-k);
}
printf("\n");
}
}
return 0;
}