dinic
搞个虚拟源点和汇点,瞎建建边就好辣。
偷张图↓↓
如果没满流就是无解辣
输出方案咋办呢?
枚举每种类型,蓝后枚举它们的边
如果该边被使用了(通过判断反向边的流量),且连接的另一点不是汇点
那么就找到一个被用的题了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
inline int Min(int a,int b){return a<b?a:b;}
void read(int &x){
static char c=getchar();x=;
while(c<''||c>'') c=getchar();
while(''<=c&&c<='') x=x*+(c^),c=getchar();
}
#define N 1050
#define M 210000
int n,m,k,S,T,d[N],cur[N]; bool vis[N];
int cnt=,hd[N],nxt[M],ed[N],poi[M],val[M];
queue <int> h;
void adde(int x,int y,int v){
nxt[ed[x]]=++cnt; hd[x]=hd[x]?hd[x]:cnt;
ed[x]=cnt; poi[cnt]=y; val[cnt]=v;
}
bool bfs(){
memset(vis,,sizeof(vis));
h.push(S); vis[S]=; d[S]=;
while(!h.empty()){
int x=h.front(); h.pop();
for(int i=hd[x];i;i=nxt[i]){
int to=poi[i];
if(!vis[to]&&val[i]>){
vis[to]=; d[to]=d[x]+;
h.push(to);
}
}
}return vis[T];
}
int dfs(int x,int a){
if(x==T||a==) return a;
int f,F=;
for(int &i=cur[x];i&&a;i=nxt[i]){
int to=poi[i];
if(d[to]==d[x]+&&(f=dfs(to,Min(a,val[i])))>)
a-=f,F+=f,val[i]-=f,val[i^]+=f;
}return F;
}
int dinic(){
int re=;
while(bfs()){
for(int i=;i<=T;++i) cur[i]=hd[i];
re+=dfs(S,1e9);
}return re;
}
inline void link(int x,int y,int v){adde(x,y,v),adde(y,x,);}
int main(){
read(k);read(n); register int i,j,q;
S=n+k+; T=S+;
for(i=;i<=k;++i) read(q),m+=q,link(i+n,T,q);
for(i=;i<=n;++i){
read(j); link(S,i,);
while(j--) read(q),link(i,q+n,);
}
if(dinic()!=m){puts("No Solution!");return ;}
for(i=;i<=k;++i){
printf("%d:",i);
for(j=hd[i+n];j;j=nxt[j])
if(poi[j]!=T&&val[j])
printf(" %d",poi[j]);
printf("\n");
}return ;
}