网络流相关定理

相关算法
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的即为无向边定向的方向. 然后把每条定向的无向边和原来输入的有向边建图加起. 跑一次欧拉回路即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值