P2763 试题库问题

题目描述

«问题描述:

假设一个试题库中有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

 

 

 

//感觉做此题最大的障碍就是看不下题面去233
//开一个超级源点,向每种试卷类型连边,边权为这种类型需要的试卷数量
//然后试卷类型向试卷连边,边权为1
//试卷向超级汇点连边,边权为1 

//怎么输出方案。。。
//emmmmm.......想想 
//枚举每种试卷类型,看看与它相连的试卷的边的边权==0?
//......试一下 

//OK,过了
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<string> #include<algorithm> #include<queue> using namespace std; inline int read() { char c=getchar();int num=0; for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num; } const int N=1e4+5; int k,n,sum,S,T; int head[N],num_edge; struct Edge { int v,flow,nxt; }edge[N]; inline void add_edge(int u,int v,int flow) { edge[++num_edge].v=v; edge[num_edge].flow=flow; edge[num_edge].nxt=head[u]; head[u]=num_edge; } int dep[N],from[N]; bool bfs() { queue<int> que; que.push(S); for(int i=S;i<=T;++i) from[i]=head[i],dep[i]=0; dep[S]=1; int now,v; while(!que.empty()) { now=que.front(),que.pop(); for(int i=head[now];i;i=edge[i].nxt) { v=edge[i].v; if(!dep[v]&&edge[i].flow) { dep[v]=dep[now]+1; if(v==T) return 1; que.push(v); } } } return 0; } int dfs(int u,int flow) { if(u==T||!flow) return flow; int outflow=0,tmp; for(int i=head[u],v;i;i=edge[i].nxt) { v=edge[i].v; if(dep[v]!=dep[u]+1||!edge[i].flow) continue; tmp=dfs(v,min(flow,edge[i].flow)); if(!tmp) continue; edge[i].flow-=tmp; edge[i^1].flow+=tmp; flow-=tmp; outflow+=tmp; if(!flow) return outflow; } dep[u]=-1; return outflow; } int paper[20][N]; int main() { num_edge=1; k=read(),n=read(); for(int i=1,x;i<=k;++i) { x=read(),sum+=x; add_edge(S,i,x); add_edge(i,S,0); } T=sum+n+1; for(int i=sum+1,p,x;i<=n+sum;++i) { p=read(); while(p--) { x=read(); add_edge(x,i,1); add_edge(i,x,0); } add_edge(i,T,1); add_edge(T,i,0); } int ans=0; while(bfs()) { ans+=dfs(S,0x7fffffff); } if(ans!=sum) puts("No Solution!"); else { for(int A=1;A<=k;++A) { for(int i=head[A],v;i;i=edge[i].nxt) { v=edge[i].v; if(v==S) continue; if(!edge[i].flow) paper[A][++paper[0][A]]=v-sum; } } for(int i=1;i<=k;++i) { printf("%d: ",i); for(int j=1;j<=paper[0][i];++j) { printf("%d ",paper[i][j]); } puts(""); } } return 0; }

 

posted @ 2018-05-13 09:45  whymhe  阅读(202)  评论(0编辑  收藏  举报