​传送门​

源点向每个试题连边 , 每个试题向类型连边 , 类型向汇点连边 , 流量为个数

这样如果最大流是需要的总和,就是有解的 , 将方向边不为0的点输出就可以了


#include<bits/stdc++.h>
#define N 5050
#define M 100050
#define inf 0x3fffffff
using namespace std;
int first[N],next[M],to[M],w[M],tot=1;
int n,k,st,ed,dis[N],vis[N],ans,cnt;
vector<int> V[N];
void add(int x,int y,int z){
next[++tot]=first[x],first[x]=tot,to[tot]=y,w[tot]=z;
next[++tot]=first[y],first[y]=tot,to[tot]=x,w[tot]=0;
}
bool bfs(){
memset(dis,127,sizeof(dis));
memset(vis,0,sizeof(vis));
dis[st]=0 , vis[st]=1; int Inf = dis[1];
queue<int> q; q.push(st);
while(!q.empty()){
int x=q.front(); q.pop();
for(int i=first[x];i;i=next[i]){
int t=to[i]; if(!vis[t] && w[i]){
vis[t]=1; dis[t]=dis[x]+1;
q.push(t);
}
}
}return dis[ed] != Inf;
}
int dfs(int u,int flow){
if(u==ed) return flow;
int ans=0;
for(int i=first[u];i;i=next[i]){
int t=to[i];
if(dis[t]==dis[u]+1 && w[i]){
int delta=dfs(t,min(w[i],flow));
flow -= delta; ans += delta;
w[i] -= delta; w[i^1] += delta;
if(flow==0) break;
}
}return ans;
}
void dinic(){
while(bfs()) ans+=dfs(st,inf);
}
int main(){
cin>>k>>n; st=0,ed=n+k+1;
for(int i=1;i<=k;i++){
int x; scanf("%d",&x); add(i+n,ed,x); cnt += x;
}
for(int i=1;i<=n;i++){
add(st,i,1);
int x; scanf("%d",&x);
for(int j=1;j<=x;j++){
int y; scanf("%d",&y); add(i,y+n,1);
}
}
dinic(); if(ans != cnt){printf("No Solution!"); return 0;}
for(int i=n+1;i<=n+k;i++){
for(int j=first[i];j;j=next[j]){
if(j&1 && w[j]) V[i-n].push_back(to[j]);
}
}
for(int i=1;i<=k;i++){
printf("%d: ",i);
int siz=V[i].size();
for(int j=0;j<siz;j++) printf("%d ",V[i][j]);
printf("\n");
} return 0;
}