poj3281_网络流_EK算法
题意:分配问题,有F种食物,D种饮料,N头牛,每头牛有自己喜欢的吃的和喝的东西,现在让你去分配,使得吃喝都得到的牛最多。每种吃喝的东西只能招待一头牛。
分析:把一头牛拆成两头,一头和食物连,一头和饮料连,当然这两头牛之间肯定要连一条边,添加一个源点汇点分别向食物和饮料连。这里把牛拆成两个点是为了限制进过牛的流最大为1,这样就可以通过求最大流来得到答案。
举例说明为什么要拆牛:(见discuss)
比如只有1条牛,1 2 两种食物,1 2两种水
那图会是下边那样的
食物1 食物2
| |
| |
-----> 牛 <----
/ \
/ \
水1<--| |----> 水2
对应的输入数据是
1 2 2
2 2 1 2 1 2
这时候答案为2了WA了,因为没有拆点,所以导致一头牛享受了两套美餐,这怎么可以呢
而拆成下边那样就对了
食物1 食物2
| |
| |
--> 牛1<---
/
/
\
|-->还是牛1
/ \
/ \
水1<--| |-----> 水2
至于要拆牛,而不是拆食物的原因:因为一头牛只能选一种食物和饮料,把牛拆了,中间的容量为1.这样可以保证它只选一种。如果不拆牛的话不能保证。
刚学习了EK算法,这个题用的是邻接矩阵的EK算法。
代码:
View Code
1 #include <iostream> 2 #include <stdio.h> 3 #include <memory.h> 4 #include <queue> 5 using namespace std; 6 const int maxdata=(1<<30); //!!! 7 const int maxnum=405; 8 int f[maxnum][maxnum]; 9 int pre[maxnum]; 10 int cf[maxnum]; 11 int food,d,n; 12 queue<int> q; 13 14 void Init() 15 { 16 int i,j; 17 memset(f,0,sizeof(f)); 18 scanf("%d%d%d",&n,&food,&d); 19 20 for(i=1;i<=food;i++) 21 f[0][i]=1; 22 for(i=1;i<=n;i++) 23 f[i+food][i+food+n]=1; 24 for(i=1;i<=d;i++) 25 f[i+food+n+n][food+n+n+d+1]=1; 26 27 28 int fnum,dnum,ftemp,dtemp; 29 for(i=1;i<=n;i++) 30 { 31 scanf("%d%d",&fnum,&dnum); 32 for(j=1;j<=fnum;j++) 33 { 34 scanf("%d",&ftemp); 35 f[ftemp][i+food]=1; 36 } 37 for(j=1;j<=dnum;j++) 38 { 39 scanf("%d",&dtemp); 40 f[i+food+n][food+n+n+dtemp]=1; 41 } 42 } 43 } 44 45 int bfs(int s,int e) 46 { 47 int i,t; 48 while(!q.empty()) 49 q.pop(); 50 for(i=s;i<=e;i++) 51 pre[i]=-1; 52 53 cf[s]=maxdata; 54 q.push(s); 55 while(!q.empty()) 56 { 57 t=q.front(); 58 q.pop(); 59 if(t==e) //!!! 60 break; 61 for(i=s;i<=e;i++) 62 { 63 if(i!=t && f[t][i]>0 && pre[i]==-1) 64 { 65 pre[i]=t; 66 cf[i]=min(f[t][i],cf[t]); 67 q.push(i); 68 } 69 } 70 } 71 if(pre[e]==-1) 72 return -1; 73 return cf[e]; 74 } 75 76 int Maxflow(int s,int e) 77 { 78 int p,q; 79 int ans=0; 80 int sum=0; 81 while(1) 82 { 83 ans=bfs(s,e); 84 if(ans==-1) 85 break; 86 q=e; 87 while(q!=s) 88 { 89 p=pre[q]; 90 f[p][q]-=ans; 91 f[q][p]+=ans; 92 q=p; 93 } 94 sum+=ans; 95 } 96 return sum; 97 } 98 99 int main() 100 { 101 Init(); 102 printf("%d\n",Maxflow(0,food+n+n+d+1)); 103 return 0; 104 } 105 106 /* 107 4 3 3 108 2 2 1 2 1 3 109 2 2 2 3 1 2 110 2 2 1 3 1 2 111 2 1 1 3 3 112 */
tjuoj 2823