#include<iostream>
#include<vector>
#include<list>
#include<queue>
#include<algorithm>
#include<limits.h>
using namespace std;
class Edge {
public:
//边的起点,终点,剩余的承载量
int from;
int to;
int available;
Edge(int a, int b, int c) {
from = a;
to = b;
available = c;
}
};
class Dinic {
public:
//N代表有多少个点
int N;
//nexts中存放第i个城市所有的边在edges的下标
vector<vector<int>>nexts;
vector<Edge>edges;
//优化,高度数组,哪些边可以跳过
vector<int> depth;
vector<int> cur;
//初始化
Dinic(int nums)
{
N = nums + 1;
nexts.resize(N + 1, vector<int>());
depth.resize(N);
cur.resize(N);
}
//加入边,从u到v代价为r
void addEdge(int u, int v, int r)
{
//原来的size为m,最后一条边下标为m-1
//加上一条边,新加的边其下标就是m
int m = edges.size();
edges.push_back(Edge(u, v, r));
//u这座城市有一条边对应edges的下标m
nexts[u].push_back(m);
//补一条反向边
edges.push_back(Edge(v, u, 0));
//v能到新加的那条反向边,下标为m+1
nexts[v].push_back(m + 1);
}
//最大网络流算法
//从s到t求最大的网络流
int maxFlow(int s, int t)
{
int flow = 0;
//不断寻找从s到t每条路径上的网络流
//如果有则bfs返回ture
while (bfs(s, t))
{ //重新给cur赋值为0
fill(cur.begin(), cur.end(), 0);
flow += dfs(s, t, INT_MAX);
fill(depth.begin(), depth.end(), 0);
}
return flow;
}
//宽度优先遍历
bool bfs(int s, int t)
{
//s位置在高度数组中是第0层
depth[s] = 0;
list<int>queue;
queue.push_front(s);
vector<bool>visited(N,false);
visited[s] = true;
while (!queue.empty())
{
//拿出第u个节点,并且能够从nexts数组中找到其所有的边
int u = queue.back();
queue.pop_back();
for (int i = 0; i < nexts[u].size(); i++)
{
Edge& e = edges[nexts[u][i]];
//找到其去哪
int v = e.to;
//没有去过并且还有可用负载
if (!visited[v] && e.available > 0)
{
visited[v] = true;
//终点v的高度是u+1,并且判断v是不是最终的重点t
depth[v] = depth[u] + 1;
if (v == t)
{
break;
}
queue.push_front(v);
}
}
}
return visited[t];
}
// 当前来到了s点,s可变
// 最终目标是t,t固定参数
// r,收到的任务
// 收集到的流,作为结果返回,ans <= r
int dfs(int s, int t, int r)
{
if (s == t || r == 0)
{
return r;
}
int f = 0;
int flow = 0;
// s点从哪条边开始试 -> cur[s]
for (; cur[s] < nexts[s].size(); cur[s]++)
{
//从ei这条边开始试
int ei = nexts[s][cur[s]];
//找到ei对应的边以及反向边
Edge& e = edges[ei];
Edge& o = edges[(ei ^ 1)];
//利用高度进行优化,并且下级节点能到t且额度为f
if (depth[e.to] == (depth[s] + 1) && (f = dfs(e.to, t, min(e.available, r))) != 0)
{
e.available -= f;
o.available += f;
flow += f;
r -= f;
if (r <= 0)
{
break;
}
}
}
return flow;
}
};
int k = 1;
int S, T;
int N, M;
void solve()
{
cin >> N;
cin >> S >> T >> M;
Dinic di(N);
while (M--)
{
int a, b, c;
cin >> a >> b >> c;
di.addEdge(a, b, c);
di.addEdge(b, a, c);
}
printf("Case %d: %d\n", k++, di.maxFlow(S, T));
}
int main()
{
int t;
cin >> t;
while (t--)
{
solve();
}
return 0;
}
最大网络流之Dinic 算法
最新推荐文章于 2024-09-02 16:35:28 发布