HDU 4292 Food【最大流】
题意: 有 F种食物和D种饮料,知道了每种食物和饮料的数量,有n 个人,知道了这些人分别喜欢的食物和饮料,当每个人能够吃到自己喜欢的一个食物和喝到自己喜欢
的一种饮料,他就会开心,问最多能有多少人可以开心。
分析:在 源点 和 每种食物之间 连一条边,容量为 食物的数量,将每头牛拆成两个点,将每头牛的第一个点和第二个点之间连一条容量为 1 的边,在每头牛喜欢的食物
和该牛的第一个点之间连一条容量为 1 的边,在每头牛喜欢的饮料和该牛的第二个点之间连一条容量为 1 的边,在 汇点 和每种饮料之间连一条容量为 饮料数量
的边,求最大流。
#include<stdio.h> #include<string.h> #include<stdlib.h> #define INF 0x1f1f1f1f int s,u; int c[1000][1000],r[1000][1000]; int gap[1000]; int dis[1000]; void init() { int v,x,q[1000],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[1200],low[1000]; 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 food[555]; int drink[555]; char ok[222][222]; char tt[222]; int main() { int i,D,F,N,f,d,k,j; while(scanf("%d%d%d",&N,&F,&D)!=EOF) { memset(c,0,sizeof(c)); s=1; u=2+N*2+F+D; for(i=1;i<=F;i++) scanf("%d",&food[i]); for(i=1;i<=D;i++) scanf("%d",&drink[i]); for(i=2;i<=1+F;i++) c[s][i]=food[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]=drink[i-F-2*N-1]; for(i=1;i<=N;i++) { scanf("%s",tt+1); for(j=1;j<=F;j++) if(tt[j]=='Y') c[1+j][F+1+i]=1; } for(i=1;i<=N;i++) { scanf("%s",tt+1); for(j=1;j<=D;j++) if(tt[j]=='Y') c[F+1+N+i][F+1+2*N+j]=1; } printf("%d\n",max_flow()); } return 0; }