题目链接:luogu2763
题目描述
«问题描述:
假设一个试题库中有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!”。
输入输出样例
输入样例:
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
这个题与圆桌游戏基本是一样的,对于每个试题i,如果i可以属于p类,就将p向其连一条流量为1的边。然后按照惯例设一个源点S和汇点T,从S向每个题库连一个流量为题库所需试题多少的边。
然后将每道题与汇点连一条容量为1的边。跑一边最大流,如果最大流等于每个题库的要求量之和,那么就有解,否则无解。然后去遍历每个题库所连的边,如果这些边的容量变为了0。那么就说明这条边所连向的题可以属于这个题库,将其输出即可。
代码:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<queue> 5 using namespace std; 6 const int N=10600*2,INF=0x7fffffff; 7 queue<int>q; 8 int k,n,head[N],S,T,ejs,W,dep[N]; 9 char ch; 10 char buf[1000000],*p1=buf,*p2=buf; 11 #define nc() \ 12 p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2) ? EOF :*p1++; 13 #define read(x) \ 14 x=0;ch=nc(); \ 15 while(!isdigit(ch)) ch=nc();\ 16 while(isdigit(ch))x=x*10+ch-'0',ch=nc(); 17 inline int change(int x) 18 { 19 return x%2?x+1:x-1; 20 } 21 struct node 22 { 23 int v,nxt,w; 24 }edg[N]; 25 void add(int u,int v,int w) 26 { 27 edg[++ejs].v=v;edg[ejs].w=w;edg[ejs].nxt=head[u];head[u]=ejs; 28 edg[++ejs].v=u;edg[ejs].w=0;edg[ejs].nxt=head[v];head[v]=ejs; 29 } 30 bool bfs() 31 { 32 memset(dep,0,sizeof(dep)); 33 while(!q.empty()) q.pop(); 34 q.push(S); 35 dep[S]=1; 36 while(!q.empty()) 37 { 38 int u=q.front(); 39 q.pop(); 40 for(int i=head[u];i;i=edg[i].nxt) 41 { 42 int v=edg[i].v; 43 if(!dep[v]&&edg[i].w) 44 { 45 dep[v]=dep[u]+1; 46 q.push(v); 47 if(v==T) return 1; 48 } 49 } 50 } 51 return 0; 52 } 53 int dfs(int u,int dist) 54 { 55 if(u==T) return dist; 56 int di=0; 57 for(int i=head[u];i;i=edg[i].nxt) 58 { 59 int v=edg[i].v; 60 if(di==dist) return di; 61 if(edg[i].w&&dep[v]==dep[u]+1) 62 { 63 int kk=dfs(v,min(dist,edg[i].w)); 64 if(kk) 65 { 66 di+=kk; 67 edg[i].w-=kk; 68 edg[change(i)].w+=kk; 69 } 70 } 71 } 72 return di; 73 } 74 int dinic() 75 { 76 int kk,ans=0; 77 while(bfs()) 78 { 79 kk=dfs(S,INF); 80 while(kk) 81 { 82 ans+=kk; 83 kk=dfs(S,INF); 84 } 85 } 86 return ans; 87 } 88 int main() 89 { 90 //freopen("data4.in","r",stdin); 91 read(k); 92 read(n); 93 n+=k; 94 S=0,T=n+1; 95 for(int i=1;i<=k;++i) 96 { 97 int x; 98 read(x); 99 W+=x; 100 add(S,i,x); 101 } 102 for(int i=k+1;i<=n;++i) 103 { 104 int p; 105 read(p); 106 for(int j=1;j<=p;++j) 107 { 108 int x; 109 read(x); 110 add(x,i,1); 111 } 112 } 113 for(int i=k+1;i<=n;++i) 114 add(i,T,1); 115 if(dinic()!=W) 116 { 117 printf("No Solution!"); 118 return 0; 119 } 120 for(int i=1;i<=k;++i) 121 { 122 printf("%d: ",i); 123 for(int j=head[i];j;j=edg[j].nxt) 124 { 125 int v=edg[j].v; 126 if(!edg[j].w&&v!=S) 127 printf("%d ",v-k); 128 } 129 printf("\n"); 130 } 131 return 0; 132 }