[网络流入门,简单题]poj1273Drainage Ditches最大流

最大流第一题.哦也~~~~~~~~~凭自己的理解写的代码,多做点题,应该会好一点.........

这是EK算法, 根据某网友的描述,该叫"方法",因为实现方式可以多样.最重要的是这个算法的思想. 算法思想源于贪心:

首先从起点开始寻找到终点的可行路,并让其满流.同时建立反向边.比如这题的数据

5条边,4个节点

1 2 40
1 4 20
2 4 20
2 3 30
3 4 10
然后我们随便找了一条路1->2->3->4满流流量为10,建立反向边4->3,3->2,2->1流量为10,并且原正向边容量直接减掉10(在各种帖子里,都用神马f,c函数来搞,我都搞晕了)

然后就这样不断地找增广路,建边.最后就得到答案了.这贪心的关键还在于建反向边,有一篇帖子对其中的理解我表示非常敬佩,至少在我看了若干帖子若干博客若干PPT后

都没明白,却因为这篇博客懂了些.参看:http://blog.sina.com.cn/s/blog_6cf509db0100uy5n.html

看完了基本就能理解这算法的奥妙之处了.总之在各种博客各种教学贴中,大家都是一个语调,我了个擦,这让毫无基础的我情何以堪.前几天有个退役的老队员来讲课,我靠,这

尼玛默认我学过图论呐(=@__@=) ............哎哎哎哎,好吧,从简单的入手,一步一步学....

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <climits>
using namespace std;
const int MAX_V = 208;
const int MAX_E = 208;
const int INF = INT_MAX>>2;//INF完全可以自己设置成100万这样子....写INT_MAX是为了装逼

bool vis[MAX_V];	//用于BFS时的标记
int G[MAX_V][MAX_V];	//邻接矩阵,G[i][j]表示从i到j的残余容量,初始为容量
						//这里不用f反向边了,而是直接加到原图中
int prev[MAX_V]; //用于BFS保存增广路,前继节点
/*
比如我们找到的增广路是1->2->3->4,当然在我的实现中编号是0->1->2->3,prev数组就会保存成这个
样子: prev[3] = 2, prev[2] = 1, prev[1] = 0, prev[0] = -1;那BFS返回后如果返回值是true就可以直接利用这个数组还原出路径来了.
又比如增广路是0->6->8->19,那数组中应该是:prev[19]=8, prev[8]=6, prev[6]=0,其它都是-1,因为我们知道要找的是0->19的路径,所以我们令p等于19,
然后看一下prev[19]等于多少,等于8,那就说明倒数第二个点就是8,在令p=prev[p],得到6,那我们就知道倒数第三个点是6,然后p=prev[p],倒数第四个点是0,
嘿,就等于起始点了,哈,就说明路径就是19<--8<--6<--0了,注意是反向的哦.BFS过程还是很朴素的,就和普通的广搜一样.
然后还有就是vis数组,当然需要这个标记数组,不然你找到一个环的话,程序就会卡死了,就一直在那个环里打转了
*/
int n, m;

bool BFS(int s, int t) {
	queue<int> Q;
	memset(vis, false, sizeof(vis));
	memset(prev, -1, sizeof(prev));	//no else

	Q.push(s);
	vis[s] = true;

    int now;
    while (!Q.empty()) {
        now = Q.front(); Q.pop();

		for (int i = 0; i < n; ++i) {
			if (G[now][i] > 0 && !vis[i]) {
				prev[i] = now;
				vis[i] = true;
				if (i == t) return true;
				Q.push(i);
			}
		}//for
    }
    return false;
}
/* s到t的最大流 */
int EK(int s, int t) {
	int flow = 0; //最大流
	int i, j;
	while (BFS(s, t)) {
        int d = INF, p;
        for (p = t; p != s; p = prev[p]) {
			d = min(d, G[prev[p]][p]); //d要设置为该路上各段的最小值
        }

        for (p = t; p != s; p = prev[p]) {
			G[prev[p]][p] -= d;
			G[p][prev[p]] += d;
        }
        flow += d;

	}
	return flow;
}
int main() {
	while (~scanf(" %d %d", &m, &n)) {
		memset(G, 0, sizeof(G));
		int f, t, c;
		for (int i = 0; i < m; ++i) {
			scanf(" %d %d %d", &f, &t, &c);
			G[f-1][t-1] += c;
		}

		printf("%d\n", EK(0, n-1));
	}
	return 0;
}
本文完

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值