题目;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啊,就没这么好的性质了