题目大意
给定一个网络图,求这个网络流最小割的所有情况中割去边数最少的边数
思路
首先,给一个网络图的所有边边权乘以个正数的值,最大流不变。因为并不影响偏序关系。
接着,当网络图所有边边权足够大的时候,给每个边权加上一个足够小的值,最小割割去的边一定是满足最小割时边数最少的。
因为最小割不会因为加上某权值而改变割的情况,但是会选择割数最小的。
知道这些我们就可以设计出一个构图方法。将所有边边权乘以一个极大的数\(SEED\)然后加\(1\),最后结果对\(SEED\)取模即可。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 200 + 10;
const int MAXNODE = 200 + 10;
const int MAXEDGE = 1000 + 10;
const ll INF = 0x3f3f3f3f3f3f3f3fll;
struct MaxFlow {
struct Edge {
int v, n;
ll f;
} e[MAXEDGE << 1];
int G[MAXNODE], edgeCnt;
void _add(int u, int v, ll f)
{
e[++edgeCnt].n = G[u];
G[u] = edgeCnt;
e[edgeCnt].f = f;
e[edgeCnt].v = v;
}
void add(int u, int v, ll f)
{
_add(u, v, f), _add(v, u, 0);
}
int dep[MAXNODE];
int cur[MAXNODE];
int S, T;
bool bfs()
{
memset(dep, -1, sizeof(dep));
queue<int> que;
que.push(S);
dep[S] = 0;
while (!que.empty()) {
int u = que.front();
que.pop();
cur[u] = G[u];
for (int i = G[u]; i; i = e[i].n)
if (e[i].f > 0 && dep[e[i].v] == -1) {
dep[e[i].v] = dep[u] + 1;
que.push(e[i].v);
}
}
return dep[T] != -1;
}
int dfs(int u, ll a=INF)
{
if (u == T || a == 0)
return a;
ll flow = 0;
for (int& i = cur[u]; i; i = e[i].n)
if (dep[e[i].v] == dep[u] + 1) {
ll f = dfs(e[i].v, min(a, e[i].f));
flow += f;
a -= f;
e[i].f -= f;
e[i ^ 1].f += f;
if (a <= 0)
break;
}
return flow;
}
ll dinic()
{
ll flow = 0;
while (bfs())
flow += dfs(S);
return flow;
}
void init(int s, int t)
{
S = s, T = t;
edgeCnt = 1;
memset(G, 0, sizeof(G));
}
} flow;
int main()
{
const int SEED = 1071;
ios::sync_with_stdio(0);
int T;
cin >> T;
while (T--) {
int n, m, S, T;
cin >> n >> m;
cin >> S >> T;
flow.init(S, T);
for (int i = 1; i <= m; ++i) {
int u, v, f;
cin >> u >> v >> f;
flow.add(u, v, f * SEED + 1);
}
cout << flow.dinic() % SEED << endl;
}
}