POJ3281:Dining——题解
http://poj.org/problem?id=3281
题目大意:
N牛,F种吃的D种喝的,牛可以在它喜欢的吃的喝的选一组,之后就不能选这个吃的喝的。
问最多满足多少人。
————————————————————————————
开始想过贼麻烦的方法,然后确认一下是否对查了题解。
……思想是对的,但建图建麻烦了。
这题的关键在于如何判断奶牛和吃喝是否被用过的同时保证牛能连上他喜欢的吃喝。
我们用对称性解决:
奶牛拆点,左边连吃,右边连喝,喝连汇点,吃连源点。
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<algorithm> #include<cctype> using namespace std; const int INF=2147483640; const int maxn=510; inline int read(){ int X=0,w=0; char ch=0; while(!isdigit(ch)) {w|=ch=='-';ch=getchar();} while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } int S,T; struct node{ int nxt; int to; int w; }edge[maxn*maxn]; int head[maxn],cnt=-1; void add(int u,int v,int w){ cnt++; edge[cnt].to=v; edge[cnt].w=w; edge[cnt].nxt=head[u]; head[u]=cnt; return; } int lev[maxn],cur[maxn]; bool bfs(int m){ int dui[m],r=0; for(int i=1;i<=m;i++){ lev[i]=-1; cur[i]=head[i]; } dui[0]=1,lev[1]=0; int u,v; for(int l=0;l<=r;l++){ u=dui[l]; for(int e=head[u];e!=-1;e=edge[e].nxt){ v=edge[e].to; if(edge[e].w>0&&lev[v]==-1){ lev[v]=lev[u]+1; r++; dui[r]=v; if(v==m)return 1; } } } return 0; } int dinic(int u,int flow,int m){ if(u==m)return flow; int res=0,delta; for(int &e=cur[u];e!=-1;e=edge[e].nxt){ int v=edge[e].to; if(edge[e].w>0&&lev[u]<lev[v]){ delta=dinic(v,min(edge[e].w,flow-res),m); if(delta>0){ edge[e].w-=delta; edge[e^1].w+=delta; res+=delta; if(res==flow)break; } } } if(res!=flow)lev[u]=-1; return res; } int main(){ memset(head,-1,sizeof(head)); int N=read();int F=read();int D=read(); S=1;T=2*N+F+D+2; for(int i=1;i<=F;i++){ add(S,i+1,1); add(i+1,S,0); } for(int i=1;i<=N;i++){ int s=i+F+1,e=i+F+N+1; add(s,e,1); add(e,s,0); } for(int i=1;i<=D;i++){ int s=i+N*2+F+1; add(s,T,1); add(T,s,0); } for(int i=1;i<=N;i++){ int f=read();int d=read(); for(int j=1;j<=f;j++){ int s=read()+1; int e=i+F+1; add(s,e,1); add(e,s,0); } for(int j=1;j<=d;j++){ int s=i+F+N+1; int e=read()+N*2+F+1; add(s,e,1); add(e,s,0); } } int ans=0; while(bfs(T))ans+=dinic(1,INF,T); printf("%d\n",ans); return 0; }