题目链接: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 } 
luogu2763