您的位置:首页 > 大数据 > 人工智能

POJ 1273 Drainage Ditches

2013-07-11 15:09 357 查看
题目链接:http://poj.org/problem?id=1273

解析:求最大流的一题入门题,使用的是效率不太高的EK算法,不会ek的话可以研究一下这个博客

http://www.cnblogs.com/devil-91/archive/2012/08/17/2644569.html注释的很详细



关于反向边为什么加最大流,可以看下面,(转载)

----------------------------------------------------我是分割线~\(≧▽≦)/~--------------------------------------------------

在这幅图中我们首先要增广1->2->4->6,这时可以获得一个容量为 2的流,但是如果不建立4->2反向弧的话,则无法进一步增广,最终答案为2,显然是不对的,然而如果建立了反向弧4->2,则第二次能进行 1->3->4->2->5->6的增广,最大流为3.

 

Comzyh对反向弧的理解可以说是"偷梁换柱",请仔细阅读: 在上面的例子中,我们可以看出,最终结果是1->2->5->6和1->2->4->6和 1->3->4->6.当增广完1->2->4->6(代号A)后,在增广 1->3->4->2->5->6(代号B),相当于将经过节点2的A流从中截流1(总共是2)走2->5>6,而不走2->4>6了,同时B流也从节点4截流出1(总共是1)走4->6而不是4->2->5->6,相当于AB流做加法.

 

简单的说反向弧为今后提供反悔的机会,让前面不走这条路而走别的路.

 

//EK算法
#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
#define Max 1000000000
using namespace std;

int n,m,ans;
int cap[210][210],pre[210],flow[210]; //pre[]存的是该点的前驱,flow[]是起始点到该点的最大流

int bfs(int start,int end) //每一次bfs,就找到一条由start到end的路
{
queue<int>Q;
while(!Q.empty())
Q.pop();
memset(pre,-1,sizeof(pre));
memset(flow,0,sizeof(flow));//初始化
flow[start] = Max;
pre[start] = 0;
Q.push(start);
while(!Q.empty())
{
int temp = Q.front();
Q.pop();
if(temp == end)
break;
for(int i = 1; i <= m;i++)
{
if(cap[temp][i] > 0 &&pre[i] == -1) //pre[i]==-1说明他还没进入过队列,保证bfs不会往回走
{
pre[i] = temp;
flow[i] = min(flow[temp],cap[temp][i]);
Q.push(i);
}
}
}
if(flow[end] == 0) //代表途中已经没有start到end的路了
return 0;
else
return flow[end];
}

void ek(int start,int end)
{
while(1)
{
int t = bfs(start,end); //t存储的是该路的最大流
if(t == 0)
break;
for(int k = end; k != start; k = pre[k])
{
cap[pre[k]][k] -= t; //正向边减去最大流
cap[k][pre[k]] += t; //反向边加上最大流
}
ans += t; //每一条边都要加上才是最大流
}
}

int main()
{
while(scanf("%d%d",&n,&m) != EOF)
{
memset(cap,0,sizeof(cap));
memset(pre,0,sizeof(pre));
memset(flow,0,sizeof(flow));
int a,b,c;
ans = 0;
for(int i = 1; i <= n;i++)
{
scanf("%d%d%d",&a,&b,&c);
cap[a][b] += c; //可能有多个a->b的边,则a->b的流量就是全部加在一起
// cap[b][a] -= c; //所有边的反向边都是0,若为-c的话,正向回来就是c,正向的流量就变成2*c了
}

ek(1,m);
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  EK POJ