1. 程式人生 > >【網路流24題】試題庫(二分圖+最大流)

【網路流24題】試題庫(二分圖+最大流)

傳送門

    試題庫

I think

    點集x,y分別放置試題與型別。源點向x集點連容量為1的邊,x集點向y中其所屬型別連容量為1的邊,y集點向T連容量為所需量的邊,求解最大流若等於總題數則有解。

Code

#include<cstdio>
#include<queue>
#include<vector>
using namespace std;

const int sm = 1100;
const int sn = 22000;
const int Inf = 0x3f3f3f3f;

int N,k,M,S,T,tot=1,Flw; bool
fl; int to[sn],nxt[sn],hd[sm],c[sn]; int lev[sm],cur[sm]; vector<int>Que[sm]; int Min(int x,int y) { return x<y?x:y; } void Add(int u,int v,int w) { to[++tot]=v,nxt[tot]=hd[u],hd[u]=tot,c[tot]=w; to[++tot]=u,nxt[tot]=hd[v],hd[v]=tot,c[tot]=0; } bool Bfs() { for(int i=1;i<=T;++i) lev[i]=0
; int t; queue<int>q; q.push(S);lev[S]=1; while(!q.empty()) { t=q.front(),q.pop(); for(int i=hd[t];i;i=nxt[i]) if(c[i]>0&&!lev[to[i]]) { lev[to[i]]=lev[t]+1; if(to[i]==T) return 1; q.push(to[i]); } } return
0; } int Dfs(int x,int mx) { if(x==T||!mx) return mx; int f; for(int i=cur[x]?cur[x]:hd[x];i;i=nxt[i]) { cur[x]=i; if(c[i]>0&&lev[to[i]]==lev[x]+1) if(f=Dfs(to[i],Min(mx,c[i]))) return c[i]-=f,c[i^1]+=f,f; } return 0; } void Dinic() { int f; while(Bfs()) { for(int i=1;i<=T;++i) cur[i]=0; while(f=Dfs(S,Inf)) Flw+=f; } } int main() { int u,v; scanf("%d%d",&k,&N); S=k+N+1,T=S+1; for(int i=1;i<=k;++i) { scanf("%d",&u); Add(N+i,T,u),M+=u; } for(int i=1;i<=N;++i) { scanf("%d",&v); Add(S,i,1); for(int j=1;j<=v;++j) scanf("%d",&u),Add(i,u+N,1); } Dinic(); if(Flw<M) puts("No Solution!"); else { for(int i=1;i<=N;++i) for(int j=hd[i];j;j=nxt[j]) if(to[j]!=S&&!c[j]) { Que[to[j]-N].push_back(i); break; } for(int i=1;i<=k;++i) { printf("%d:",i); for(int j=0;j<Que[i].size();++j) printf("%d ",Que[i][j]); putchar(10); } } return 0; }