网络流初步
网络流初步
贪心的说就是通过不停的搜s到t的路径,然后把所有的路径加起来。但这个贪心有点问题,自己本可以走另一条路,结果把别的路径的流量给抢了。所以增加了一个反向边的东西,有了这个东西,就给了路径反悔的机会。
Ford-Fulkerson算法
最朴素的算法(bushi),就是从s到t,一直dfs,满足条件增加流,否则退出。
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define ll long long
#define INF 0x7f7f7f7f
#define endl '\n'
#define mem(a, b) memset(a, b, sizeof(a))
#define open freopen("ii.txt", "r", stdin)
#define close freopen("oo.txt", "w", stdout)
#define IO \
ios::sync_with_stdio(false); \
cin.tie(0); \
cout.tie(0)
#define pb push_back
#define ll long long
using namespace std;
const int N = 210;
const double PI = 3.1415926535898;
///////
struct node
{
ll to;
ll cap;
ll rev;
node(ll a, ll b, ll c)
{
to = a;
cap = b;
rev = c;
}
};
vector<node> e[N];//邻接表存图
int lev[N];//顶点到原点的距离标号
int iter[N];//当前弧,在此前面的都没用了。
//构建分层图
void bfs(int s)
{
mem(lev, -1);
queue<ll> q;
lev[s]=0;
q.push(s);
while (!q.empty())
{
ll v = q.front();
q.pop();
for (int i = 0; i < e[v].size(); i++)
{
node &x = e[v][i];
if (x.cap > 0 && lev[x.to] < 0)
{
lev[x.to] = lev[v] + 1;
q.push(x.to);
}
}
}
}
//找增广路
ll dfs(ll v, ll t, ll f)
{
if (v == t)
return f;
for (int &i = iter[v]; i < e[v].size(); i++)
{
node &x = e[v][i];
if (lev[v] < lev[x.to] && x.cap > 0)
{
ll d = dfs(x.to, t, min(f, x.cap));
if (d > 0)
{
x.cap -= d;
e[x.to][x.rev].cap += d;
return d;
}
}
}
return 0;
}
//寻找最短路,先bfs构建分层图,然后dfs找增广路
ll max_flow(int s, int t)
{
ll flow = 0;
while (1)
{
bfs(s);
if (lev[t] < 0)
return flow;
mem(iter, 0);
ll f;
while ((f = dfs(s, t, INF)) > 0)
{
flow += f;
}
}
}
int main()
{
//open;
ll n, m, s, t;
scanf("%lld %lld %lld %lld", &n, &m, &s, &t);
for (int i = 0; i < m; i++)
{
ll u, v, w;
scanf("%lld%lld%lld", &u, &v, &w);
e[u].pb(node(v, w, e[v].size()));//存入边,反向边要注意小细节。
e[v].pb(node(u, 0, e[u].size() - 1));
}
ll ans = max_flow(s, t);
printf("%lld\n", ans);
return 0;
}