POJ 3281 Dining【最大流】
题意: 有 F 种食物, D 种饮料,和 N 头牛, 每头牛只吃自己喜欢的食物,喝自己喜欢的饮料,知道了每头牛喜欢哪些 食物 和 饮料,一头牛只有在可以吃到自己喜欢的食物喝到自己喜欢的饮料的情况下才会开心,问如何分配食物和饮料可以使尽量多的牛开心。
分析: 在 源点 和 每种食物之间 连一条边,容量为 1,将每头牛拆成两个点,将每头牛的第一个点和第二个点之间连一条容量为 1 的边,在每头牛喜欢的食物和该牛的第一个点之间连一条容量为 1 的边,在每头牛喜欢的饮料和该牛的第二个点之间连一条容量为 1 的边,在 汇点 和每种饮料之间连一条容量为 1 的边,求最大流。
#include<stdio.h> #include<string.h> #include<stdlib.h> #define INF 0x1f1f1f1f int s,u; int c[500][500],r[500][500]; int gap[500]; int dis[500]; void init() { int v,x,q[500],front=0,rear=0; memset(gap,0,sizeof(gap)); memset(dis,0xff,sizeof(dis)); q[rear++]=u; dis[u]=0; while(front<rear) { x=q[front++]; gap[dis[x]]++; for(v=1;v<u;v++) { if(dis[v]==-1&&c[v][x]>0) { dis[v]=dis[x]+1; q[rear++]=v; } } } } int max_flow() { init(); int flow=0,top=s,i,j,k,pre[500],low[500]; memset(low,0,sizeof(low)); while(dis[s]<u) { int flag=0; low[s]=INF; for(i=1;i<=u;i++) if(c[top][i]>0&&dis[top]==dis[i]+1&&dis[i]>=0) { flag=1; break; } if(flag) { low[i]=c[top][i]; if(low[i]>low[top]) low[i]=low[top]; pre[i]=top; top=i; if(top==u) { flow+=low[u]; j=top; while(j!=s) { k=pre[j]; c[k][j]-=low[u]; c[j][k]+=low[u]; j=k; } top=s; memset(low,0,sizeof(low)); } } else { int min=u-1; for(j=1;j<u;j++) { if(c[top][j]>0&&dis[j]+1<min&&dis[j]>=0) min=dis[j]+1; } gap[dis[top]]--; if(gap[dis[top]]==0) break; gap[min]++; dis[top]=min; if(top!=s) top=pre[top]; } } return flow; } int main() { int i,D,F,N,f,d,k; while(scanf("%d%d%d",&N,&F,&D)!=EOF) { memset(c,0,sizeof(c)); s=1; u=2+N*2+F+D; for(i=2;i<=1+F;i++) c[s][i]=1; for(i=F+2;i<=F+1+N;i++) c[i][i+N]=1; for(i=F+2*N+2;i<=F+2*N+1+D;i++) c[i][u]=1; for(i=1;i<=N;i++) { scanf("%d%d",&f,&d); while(f--) { scanf("%d",&k); c[1+k][F+1+i]=1; } while(d--) { scanf("%d",&k); c[F+1+N+i][F+1+2*N+k]=1; } } printf("%d\n",max_flow()); } return 0; }