题目描述
假设一个试题库中有n道试题。每道试题都标明了所属类别。同一道题可能有多个类别
属性。现要从题库中抽取m 道题组成试卷。并要求试卷包含指定类型的试题。试设计一个
满足要求的组卷算法。
编程任务:
对于给定的组卷要求,计算满足要求的组卷方案。
输入格式
由文件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.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
这道题,应该算是二分图匹配的变式吧?
先来试试二分图匹配的建图方法!
看做两个集合,取名无力的我选择让他们一个叫A集,一个叫B集!
A集表示需要的类型,B集表示题目
酱紫,就变成了二分图匹配的问题啦!
从A集出发有很多很多条边到B集。
用最原始的方法
假设类型一需要3道题,那么我们可以看做存在三个类型一,然后每个类型一需要一道题
对于所有的类型需要的题数都同理操作,就是正正经经的二分图匹配问题啦!
具体说说这个怎么建图:
假设,类型i需要x[i]道题目
首先,……超级源点….超级汇点
然后,把x[i]个类型i和超级源点连起来,令其容量为1
再然后,把题目和超级汇点连起来,令容量为1
接着(然后用的太多了,换个词),把类型和题目按照题目连接起来
最后,跑dinic
模仿金星老师:完美~
不过我没写过,大概会TLE?唔,无聊的时候可以写写(捂脸)
来稍微改动改动!体现网络流的优越性(雾)
咱们来把类型i的x[i]个点合并起来,令超级源点到类型i所代表的点的容量为i
然后,就跑dinic
和之前的某道题一样哟,某条边的flow==1就代表被匹配到了!
唔,顺便说一句。这样跑出来的最大流的值如果比需要的题目数量还少,就代表木有成功咯,需要输出”No Solution!”
然后就没有然后啦!和以前一样搞就可以了的说~
唔,温馨提示:注意数据范围
因为我RE了!(捂脸)
#include
#include
#include
#include
#define INF 1e8
using namespace std;
const int maxn=1505;
int n,m,s,t;
struct Edge{int from,to,cap,flow;};
vector edges(20000);
vector<int>G[maxn];
int d[maxn];
bool vis[maxn];
int k;
void AddEdge(int from,int to,int cap){
edges.push_back((Edge){from,to,cap,0});
edges.push_back((Edge){to,from,0,0});
k=edges.size();
G[from].push_back(k-2);
G[to].push_back(k-1);
}
int DFS(int x,int a){
int flow=0,f;
if(x==t || a==0) return a;
for(int i=0;iif(d[e.to]==d[x]+1 && (f=DFS(e.to,min(a,e.cap-e.flow)))>0){
e.flow+=f;
edges[G[x][i]^1].flow-=f;
a-=f;
flow+=f;
if(a==0) break;
}
}
return flow;
}
bool BFS(){
queue<int>q;
memset(vis,0,sizeof(vis));
d[s]=1;vis[s]=true;q.push(s);
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0;iif(!vis[e.to] && e.cap>e.flow){
d[e.to]=d[x]+1;
vis[e.to]=true;
q.push(e.to);
}
}
}
return vis[t];
}
int dinic(){
int flow=0;
while(BFS())
flow+=DFS(s,INF);
return flow;
}
int main(){
int sum=0;
scanf("%d%d",&n,&m);
s=0;t=n+m+1;
for(int c,i=1;i<=n;i++){
scanf("%d",&c);
AddEdge(s,i,c);
sum+=c;
}
for(int a,k,i=1;i<=m;i++){
scanf("%d",&k);
for(int j=1;j<=k;j++){
scanf("%d",&a);
AddEdge(a,i+n,1);
}
}
for(int i=n+1;i<=m;i++) AddEdge(i,t,1);
if(dinic()!=sum){puts("No Solution!");}
else{
for(int i=1;i<=n;i++){
printf("%d:",i);
for(int j=0;jif(e.to!=t && e.flow==1){
printf(" %d",e.to-n);
}
}
printf("\n");
}
}
return 0;
}