对网络流还很不熟悉,之前只做过一道模板题。这次好好理解了下。
该上手就是道比较难的,构图都不会,看了别人的题解,发现他们都推荐一篇文章(链接:http://wenku.baidu.com/view/0ad00abec77da26925c5b01c.html),个人认为看不是特别懂,因人而异吧。
比较欣赏这种(虽然最后推出结论一致,但更好理解):( http://blog.csdn.net/non_cease/article/details/6713796 )
1.将顾客作为节点。
2.取超级源点,汇点。
3.当猪圈第一次被打开时,在源点和顾客间连一条边,容量为该猪圈的头数。(实际实现过程因为,用二维数组存储,两点之间只能存一条边,故会把从源点到顾客的不同边合并)。其实,猪圈是多余的,直接跳过,从源点连向顾客。
4.当某个猪圈不是第一次打开时,在上次打开该猪圈和这次打开的顾客间连一条无穷的边,相当于前一个顾客买多了,这个顾客又在前一个顾客那买。
5.在每个顾客和源点之间连一条边,容量为该顾客想要购买的猪数,以此来限制。
最后调用EK函数求解即可。
这是结合这篇博客我自己备注的详细代码(链接:http://blog.csdn.net/neofung/article/details/6854341)
#include <iostream> #include <cstdio> #include <queue> #include <string.h> using namespace std; #define arraySize 110 #define inf 1000000000 int capacity[arraySize][arraySize],flow[arraySize][arraySize],max_flow[arraySize],pre[arraySize]; //capacity存储点之间最大流量,flow存储点之间当前已经流过的流量 //max_flow存储每次遍历过程中的值,pre记录查找过程中每个节点的前一节点,用于后续更新 int Edmonds_Karp(int source,int target)//源点,汇点 { <span style="white-space:pre"> </span>//初始化 <span style="white-space:pre"> </span>queue <int> store; <span style="white-space:pre"> </span>int ans=0,cur; <span style="white-space:pre"> </span>//cur当前节点 <span style="white-space:pre"> </span>memset(flow,0,sizeof(flow)); <span style="white-space:pre"> </span>while(true)//一直寻找增广路 <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span> memset(max_flow,0,sizeof(max_flow));<span style="white-space:pre"> </span> <span style="white-space:pre"> </span> memset(pre,0,sizeof(pre)); <span style="white-space:pre"> </span> store.push(source); <span style="white-space:pre"> </span> max_flow[source]=inf; <span style="white-space:pre"> </span> while(!store.empty()) <span style="white-space:pre"> </span> { <span style="white-space:pre"> </span> cur=store.front(); <span style="white-space:pre"> </span> store.pop(); <span style="white-space:pre"> </span> for(int next=source;next<=target;next++) <span style="white-space:pre"> </span> { <span style="white-space:pre"> </span> <span style="white-space:pre"> </span>//max_flow[next]恰可以用于标记是否访问过,同时要保证两点之间还有剩余流量 //这个过程中,可能会出现多条可行路径,但因为汇点只有一个会被先到达的路径抢占,故每个过程只能找到一条 <span style="white-space:pre"> </span> if(!max_flow[next]&&capacity[cur][next]>flow[cur][next]) { store.push(next); //如果这两个点之间的值,比之前的最小值还小,则更新 max_flow[next]=min(max_flow[cur],capacity[cur][next]-flow[cur][next]); //记录前一个节点,用于后续更新 pre[next]=cur; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span> <span style="white-space:pre"> </span> } <span style="white-space:pre"> </span> } <span style="white-space:pre"> </span> //说明已经找不到增广路了 <span style="white-space:pre"> </span> if(max_flow[target]==0)break; <span style="white-space:pre"> </span> //更新操作 <span style="white-space:pre"> </span> for(int u=target;u!=source;u=pre[u]) { flow[pre[u]][u]+=max_flow[target]; <span style="white-space:pre"> </span>//反向边 flow[u][pre[u]]-=max_flow[target]; } ans+=max_flow[target]; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>return ans; } int main() { <span style="white-space:pre"> </span>int m,n,t,tmp; <span style="white-space:pre"> </span>int flag[1010],pig[1010]; <span style="white-space:pre"> </span>memset(flag,0,sizeof(flag)); <span style="white-space:pre"> </span>scanf("%d%d",&m,&n); <span style="white-space:pre"> </span>for(int i=1;i<=m;i++) <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>scanf("%d",&tmp); //存储每个猪房的猪的数量 <span style="white-space:pre"> </span>pig[i]=tmp; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>for(int i=1;i<=n;i++) <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>scanf("%d",&t); <span style="white-space:pre"> </span>for(int j=0;j<t;j++) <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>scanf("%d",&tmp); //如果猪房第一次打开,就直接连边到第一个打开的顾客,权值为猪房内猪的数量 <span style="white-space:pre"> </span>if(flag[tmp]==0) <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>capacity[0][i]+=pig[tmp]; <span style="white-space:pre"> </span>flag[tmp]=i; <span style="white-space:pre"> </span>} //否则就在顾客之间加一条权值为无穷的边,并将状态更新到新一个顾客 <span style="white-space:pre"> </span>else <span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>capacity[flag[tmp]][i]=inf; <span style="white-space:pre"> </span>flag[tmp]=i; <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>scanf("%d",&tmp); //连一条该顾客到汇点权值为顾客要买的猪的数量的边 <span style="white-space:pre"> </span>capacity[i][n+1]=tmp; <span style="white-space:pre"> </span>} //调用EK算法求解 <span style="white-space:pre"> </span>cout<<Edmonds_Karp(0,n+1)<<endl; <span style="white-space:pre"> </span>return 0; }