POJ 1149 PIGS EK最大流

对网络流还很不熟悉,之前只做过一道模板题。这次好好理解了下。

该上手就是道比较难的,构图都不会,看了别人的题解,发现他们都推荐一篇文章(链接: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;
}

第一次自己写网络流,发现其实也不是特别难,这是EK实现,最大流还有SAP,DINIC两种实现方式。SAP是最高效的,接下来去学下,O(∩_∩)O~!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值