题目大意:
假设一个试题库中有n道试题。每道试题都标明了所属类别。同一道题可能有多个类别属性。现要从题库中抽取m 道题组成试卷。并要求试卷包含指定类型的试题。试设计一个满足要求的组卷算法。
思路:
好像题目的描述有一点问题,但是看样例就没有问题了。首先我们要知道每一个题目虽然有很多种类型,但是在试卷中只可以当做是一个类型的题目来呈现。用题目和类型连一条流量为1的边来表示这个题目可以选择这个类型来呈现,同时每一个题目和源点连一条流量为1的边表示这个题目总共只可以呈现一种类型,每一种类型和汇点连一条为这个类型题目数量的边,表示这个类型的题目上限是这么多,最后判断一下总流量是不是等于m就好了。
/*==========================
* Author : ylsoi
* Problem : luogu2763
* Algorithm : Max_Flow
* Time : 2018.7.27
* ========================*/
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;++i)
typedef long long ll;
using namespace std;
void File(){
freopen("luogu2763.in","r",stdin);
freopen("luogu2763.out","w",stdout);
}
const int maxk=20+10;
const int maxn=1000+10;
const int maxe=maxn*maxk+10;
const int inf=0x3f3f3f3f;
int ss,tt,n,k,m,ans;
int las[maxe<<1],to[maxe<<1],beg[maxe],flow[maxe<<1],cnte=1;
void add(int u,int v,int f){
las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v; flow[cnte]=f;
las[++cnte]=beg[v]; beg[v]=cnte; to[cnte]=u; flow[cnte]=0;
}
struct dinic{
int num[maxn+maxk],cur[maxn+maxk];
queue<int>qu;
bool bfs(){
memset(num,0,sizeof(num));
num[ss]=1;
qu.push(ss);
while(qu.size()){
int u=qu.front(); qu.pop();
for(int i=beg[u];i;i=las[i]){
if(!flow[i] || num[to[i]])continue;
num[to[i]]=num[u]+1;
qu.push(to[i]);
}
}
return num[tt]!=0;
}
int dfs(int u,int gap){
if(u==tt || !gap)return gap;
int ret=0,f;
for(int &i=cur[u];i;i=las[i]){
if(num[to[i]]!=num[u]+1)continue;
if((f=dfs(to[i],min(gap,flow[i])))){
gap-=f;
ret+=f;
flow[i]-=f;
flow[i^1]+=f;
}
if(!gap)break;
}
return ret;
}
void work(){
while(bfs()){
REP(i,ss,tt)cur[i]=beg[i];
ans+=dfs(ss,inf);
}
}
}T;
void init(){
scanf("%d%d",&k,&n);
ss=0; tt=n+k+1;
int u,v;
REP(i,1,k){
scanf("%d",&u);
add(n+i,tt,u);
m+=u;
}
REP(i,1,n){
add(ss,i,1);
scanf("%d",&u);
REP(j,1,u){
scanf("%d",&v);
add(i,n+v,1);
}
}
}
vector<int>fuck[maxk];
int main(){
File();
init();
T.work();
if(ans!=m)puts("No Solution!");
else{
for(int i=2;i<=cnte;i+=2){
if(to[i]==tt || to[i^1]==ss)continue;
if(flow[i])continue;
fuck[to[i]-n].push_back(to[i^1]);
}
REP(i,1,k)sort(fuck[i].begin(),fuck[i].end());
REP(i,1,k){
printf("%d: ",i);
int siz=fuck[i].size()-1;
REP(j,0,siz)printf("%d ",fuck[i][j]);
putchar('\n');
}
}
return 0;
}