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=0; while(c<'0'||c>'9') c=getchar(); while('0'<=c&&c<='9') x=x*10+(c^48),c=getchar(); } #define N 1050 #define M 210000 int n,m,k,S,T,d[N],cur[N]; bool vis[N]; int cnt=1,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,0,sizeof(vis)); h.push(S); vis[S]=1; d[S]=0; 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]>0){ vis[to]=1; d[to]=d[x]+1; h.push(to); } } }return vis[T]; } int dfs(int x,int a){ if(x==T||a==0) return a; int f,F=0; for(int &i=cur[x];i&&a;i=nxt[i]){ int to=poi[i]; if(d[to]==d[x]+1&&(f=dfs(to,Min(a,val[i])))>0) a-=f,F+=f,val[i]-=f,val[i^1]+=f; }return F; } int dinic(){ int re=0; while(bfs()){ for(int i=1;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,0);} int main(){ read(k);read(n); register int i,j,q; S=n+k+1; T=S+1; for(i=1;i<=k;++i) read(q),m+=q,link(i+n,T,q); for(i=1;i<=n;++i){ read(j); link(S,i,1); while(j--) read(q),link(i,q+n,1); } if(dinic()!=m){puts("No Solution!");return 0;} for(i=1;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(" "); }return 0; }