网络流入门1 地震逃生(算法:网络流 BFS+DFS 数据结构:链式前向星)

题目;https://www.luogu.com.cn/problem/P1343
在这里插入图片描述参考一篇题解写的代码
这里直接附上我的代码先

#include<bits/stdc++.h>
using namespace std;
const int maxn = 202;
const int maxm = 2002;

int cnt = 1;
int head[2 * maxn];//如head[a],表示以a为起点的边
int to[2 * maxm];//to是点
int nex[2 * maxm];//是边
int w[2 * maxm];

int dis[maxn];

queue<int>q;
int n, m, x, a, b, c;
void add(int a, int b, int c)	//链式前向星
{
	to[++cnt] = b;
	nex[cnt] = head[a];
	head[a] = cnt;
	w[cnt] = c;
}

bool bfs()
{
	while (!q.empty())
		q.pop();
	memset(dis, 0, sizeof dis);
	q.push(1);
	dis[1] = 1;
	while (!q.empty())
	{
		int x = q.front();
		q.pop();
		for (int i = head[x]; i; i = nex[i])
		{
			if (w[i] && (!dis[to[i]]))
			{
				dis[to[i]] = dis[x] + 1;
				q.push(to[i]);
				if (to[i] == n)
					return true;
			}
			
		}
	}
	return false;
}

int dfs(int x, int flow)	//其中的x为当前点,flow可视为流入的最大流,res可视为囤积在此点流量,故flow-res即为流出的最大流量
{
	if (x == n)
		return flow;
	int res = flow;
	int k;
	for (int i = head[x]; i; i = nex[i])
	{
		if ((dis[to[i]] == dis[x] + 1) && (w[i]))
		{
			k = dfs(to[i], min(res, w[i]));
			if (k != 0)
				dis[to[i]] = 0;
			w[i] -= k; w[i ^ 1] += k;
			res -= k;
		}
	}
	return (flow - res);
}

void debug()
{
	for (int i = 0; i <= 25; i++)
		cout << "i:" << i << " nex:" << nex[i] << " hd:" << head[i] << " to:" << to[i] << " val:" << w[i] << endl;
	for (int i = 1; i <= n; i++)
		cout << "dis:" << dis[i] << endl;
}

int main()
{
	cin >> n >> m >> x;
	for (int i = 0; i < m; i++)
	{
		cin >> a >> b >> c;
		add(a, b, c);
		add(b, a, 0);
	}
	int re = 0;
	while (bfs())
	{
		re += dfs(1, INT_MAX);
		//debug();
	}

	if (re)
		cout << re << ' ' << (x - 1) / re + 1 << endl;
	else
		cout << "Orz Ni Jinan Saint Cow!\n";
}

建图的方式是用链式前向星,第一次用,也是第一次学,真的很有意思的一个数据结构,特别是对图的边和点的处理,都非常棒,附上我的链式前向星学习链接
https://blog.csdn.net/sugarbliss/article/details/86495945?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522164645924816780357247121%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=164645924816780357247121&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~rank_v31_ecpm-1-86495945.pc_search_result_cache&utm_term=%E9%93%BE%E5%BC%8F%E5%89%8D%E5%90%91%E6%98%9F&spm=1018.2226.3001.4187

最后来说说我自己的问题,毕竟debug de了我一天
在bfs的代码中

for (int i = head[x]; i; i = nex[i])
		{
			if (w[i] && (!dis[to[i]]))
			{
				dis[to[i]] = dis[x] + 1;
				q.push(to[i]);
				if (to[i] == n)
					return true;
			}
			
		}

我开始写成了这样:

for (int i = head[x]; i; i = nex[i])
		{
			if (w[i] && (!dis[to[i]]))
			{
				dis[to[i]] = dis[x] + 1;
				q.push(to[i]);
			}
			if (to[i] == n)
					return true;
			
		}

emm性质就完全变了,当时自己死活都看不出来,最后找到的原因是选择另外一种找错的方法,就是以题解为标准,一步步把题解的代码改成我代码的样子!这样子才发现了。
为什么if要在上一个if里面的原因也很简单,就是,路存在,但是走不通了,就是w=0
网络流还是挺有意思的,无限的DFS搜索最后,最后总能慢慢收敛,特别是构建反向图的步骤,真的是非常巧妙

啊对了,为什么一开始的cnt要取1呢,取0不好么?取其他数不好么?为什么一初始还要前缀++啊,这也困扰了我许久,但是最后还是想明白了,cnt无论取何值其实都没什么影响对遍历来说,有影响的是求取反向边的时候,如果cnt一开始取奇数的话,那第一条边cnt就是2,第二条边就是3,用1异或下就是轻松的得到反向边啦,但是如果一开始cnt一开始取偶数,比如0啊,10啊,就没这么好的性质了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值