相关算法
Dinic算法(最大流)
EK算法(SPFA)(费用流)
EK算法(Dij)(费用流)
预流推进(最大流)
上下限网络流模型
最大权闭合子图(最大权闭包)
有向图每个点都有一个权值(可能含负权,不然这个这个问题就没什么意义了),求一个权值和最大的闭合子图。
解法:
对于负权点,往T点连一个容量为点权绝对值的边。对于正权点,从S点连一条容量为点权的边。原图所有边原样连接,权值为inf。最后答案是全体正权和-最小割。于S相连的、不与T相连的边是在子图中的点。
常见的模型就是,对于一定花费,会有特定的收益。为最大收益是多少。
网络流输出割集
(以下必须建无向边)
在残流图上从S点dfs,所有能到达的点是S集,否则是T集。
在残流图上从T点dfs,所有能到达的点是T集,否则是S集。
这里值得注意的是两者所搜出的集合不一定相同!但是由此的两种分割一定满足最小割。
但是在残流图上不存在这么一个点:它既可以被S搜到,又可以被T搜到。因为这样经过这个点还可以进行增广路,残流图就不是最大流。只存在这样点:它可以被S、T其中的一个搜到,或者S、T都搜不到。而对于都搜不到的点。它既可以属于S集,也可属于T集。(如果不存在搜不到的点,最小割就是唯一的【 ZOJ 2587 】)
网络流关键割边
(1)增加那些边的容量可以让最大流增大。
在残流图,从S、T点分别dfs一遍,分别染色。两个端点横跨两个集合的边是关键边,关键边一定是割边。
(2)减少那些点的容量可以让最大流减少(必须为无向图)。
在残流图上跑tarjan强连通。两端点在一个联通分量的边是关键边(也就是说二分图找关键边对于一般的图来说同样适用)
全局最小割(没用网络流)
全局最小割是指,把一个图分成两个不同联通块所需要的最小割集这有Stoer Wagne算法。
/*
Stoer_Wagner算法, 时间复杂度是O(n^3)
*/
// 洛谷 P5632
const int maxn = 550;
const int inf = 1000000000;
int n, r;
int edge[maxn][maxn], dist[maxn];
bool vis[maxn], bin[maxn];
void init()
{
memset(edge, 0, sizeof(edge));
memset(bin, false, sizeof(bin));
}
int contract( int &s, int &t ) // 寻找 s,t
{
memset(dist, 0, sizeof(dist));
memset(vis, false, sizeof(vis));
int i, j, k, mincut, maxc;
for(i = 1; i <= n; i++)
{
k = -1; maxc = -1;
for(j = 1; j <= n; j++)if(!bin[j] && !vis[j] && dist[j] > maxc)
{
k = j; maxc = dist[j];
}
if(k == -1)return mincut;
s = t; t = k;
mincut = maxc;
vis[k] = true;
for(j = 1; j <= n; j++)if(!bin[j] && !vis[j])
dist[j] += edge[k][j];
}
return mincut;
}
int Stoer_Wagner()
{
int mincut, i, j, s, t, ans;
for(mincut = inf, i = 1; i < n; i++)
{
ans = contract( s, t );
bin[t] = true;
if(mincut > ans)mincut = ans;
if(mincut == 0)return 0;
for(j = 1; j <= n; j++)if(!bin[j])
edge[s][j] = (edge[j][s] += edge[j][t]);
}
return mincut;
}
int main()
{
int m, a, b, c;
while(~ scanf("%d%d", &n, &m))
{
memset(edge, 0, sizeof edge);
for(int i = 0; i < m; i++)
{
scanf("%d%d%d", &a, &b, &c);
edge[a][b] += c, edge[b][a] += c;
}
printf("%d\n", Stoer_Wagner());
}
return 0;
}
最小、最大权环完全覆盖问题
给你一个N个顶点M条边的带权有向图,要你把该图分成一个或多个不相交的有向环。且所有定点都被有向环覆盖。
将图拆成4的点i0、i1、i2、i3。建边<s, i0, 1, 0>, <i3, t, 1, 0>, <i0, i1, 1, 0> <i2, i3, 1, 0> 当原图<i, j, w>边存在时, 建边<i1, j2, 1, w>。最后在这个图上跑最小费、最大费费用流。答案就是费用流答案。其中如果流量小于n。 是无解的。这个方法对无向图也适用(建两个边即可)。
混和图欧拉回路
混合图:一个包含有向边、无向边的图,求欧拉回路
首先是对图中的无向边随意定一个方向,然后统计每个点的入度(indeg)和出度(outdeg),
如果(indeg - outdeg)是奇数的话,一定不存在欧拉回路;此后:
1,对于有向边,舍弃;
对于无向边,就按照最开始指定的方向建权值为 1 的边;
2,对于入度小于出度的点,从源点连一条到它的边,权值为(outdeg - indeg)/2;
出度小于入度的点,连一条它到汇点的权值为(indeg - outdeg)/2 的边;
构图完成,如果满流(求出的最大流值 == 和汇点所有连边的权值之和),那么存在欧拉回路,否则不存在。残留网络上,边流大于0的即为无向边定向的方向. 然后把每条定向的无向边和原来输入的有向边建图加起. 跑一次欧拉回路即可。