hihoCoder1378 (最大流最小割)

#1378 : 网络流二·最大流最小割定理

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

小Hi:在上一周的Hiho一下中我们初步讲解了网络流的概念以及常规解法,小Ho你还记得内容么?

小Ho:我记得!网络流就是给定了一张图G=(V,E),以及源点s和汇点t。每一条边e(u,v)具有容量c(u,v)。网络流的最大流问题求解的就是从s到t最多能有多少流量。

小Hi:那这个问题解决办法呢?

小Ho:解决网络流的基本思路就是寻找增广路,不断更新残留网络。直到找不到新的增广路,此时得到的流就是该网络的最大流。

小Hi:没错,看来你记得很牢嘛。

小Ho:哎嘿嘿,不过这里我有一个问题,为什么找不到增广路时就已经找到了最大流呢?

小Hi:这一次我就来解决你的疑惑,首先我们要从网络流的割开始讲起。

对于一个网络流图G=(V,E),其割的定义为一种点的划分方式:将所有的点划分为S和T=V-S两个部分,其中源点s∈S,汇点t∈T。

对于一个割(S,T),我们定义净流f(S,T)表示穿过割(S,T)的流量之和,即:

f(S,T) = Σf(u,v) | u∈S,v∈T

举个例子(该例子选自算法导论):

净流f = f(2,4)+f(3,4)+f(3,5) = 12+(-4)+11 = 19

同时我们定义割的容量C(S,T)为所有从S到T的边容量之和,即:

C(S,T) = Σc(u,v) | u∈S,v∈T

同样在上面的例子中,其割的容量为:

c(2,4)+c(3,5)=12+14=26

小Ho:也就是说在计算割(S,T)的净流f(S,T)时可能存在反向的流使得f(u,v)<0,而容量C(S,T)一定是非负数。

小Hi:你这么说也没错。实际上对于任意一个割的净流f(S,T)总是和网络流的流量f相等。比如上面例子中我们改变一下割的方式:

可以计算出对于这两种情况净流f(S,T)仍然等于19。

一个直观的解释是:根据网络流的定义,只有源点s会产生流量,汇点t会接收流量。因此任意非s和t的点u,其净流量一定为0,也即是Σ(f(u,v))=0。而源点s的流量最终都会通过割(S,T)的边到达汇点t,所以网络流的流f等于割的静流f(S,T)。

严格的证明如下:

f(S,T) = f(S,V) - f(S,S)
从S到T的流等于从S到所有节点的流减去从S到S内部节点的流
f(S,T) = f(S,V)
由于S内部的节点之间存在的流一定有对应的反向流,因此f(S,S)=0
f(S,T) = f(s,V) + f(S-s,V)
再将S集合分成源点s和其他属于S的节点
f(S,T) = f(s,V)
由于除了源点s以外其他节点不会产生流,因此f(S-s,V)=0
f(S,T) = f(s,V) = f

所以f(S,T)等于从源点s出来的流,也就是网络的流f。

小Ho:简单理解的话,也就是说任意一个割的净流f(S,T)都等于当前网络的流量f

小Hi:是这样的。而对于任意一个割的净流f(S,T)一定是小于等于割的容量C(S,T)。那也即是,对于网络的任意一个流f一定是小于等于任意一个割的容量C(S,T)。

而在所有可能的割中,存在一个容量最小的割,我们称其为最小割

这个最小割限制了一个网络的流f上界,所以有:

对于任一个网络流图来说,其最大流一定是小于等于最小割的。

小Ho:但是这和增广路又有什么关系呢?

小Hi:接下来就是重点了。利用上面讲的知识,我们可以推出一个最大流最小割定理

对于一个网络流图G=(V,E),其中有源点s和汇点t,那么下面三个条件是等价的:
1. 流f是图G的最大流
2. 残留网络Gf不存在增广路
3. 对于G的某一个割(S,T),此时f = C(S,T)

首先证明1 => 2

我们利用反证法,假设流f是图G的最大流,但是残留网络中还存在有增广路p,其流量为fp。则我们有流f‘=f+fp>f。这与f是最大流产生矛盾。

接着证明2 => 3

假设残留网络Gf不存在增广路,所以在残留网络Gf中不存在路径从s到达t。我们定义S集合为:当前残留网络中s能够到达的点。同时定义T=V-S。
此时(S,T)构成一个割(S,T)。且对于任意的u∈S,v∈T,有f(u,v)=c(u,v)。若f(u,v)<c(u,v),则有Gf(u,v)>0,s可以到达v,与v属于T矛盾。
因此有f(S,T)=Σf(u,v)=Σc(u,v)=C(S,T)。

最后证明3 => 1

由于f的上界为最小割,当f到达割的容量时,显然就已经到达最大值,因此f为最大流。

这样就说明了为什么找不到增广路时,所求得的一定是最大流。

小Ho:原来是这样,我明白了。

输入

第1行:2个正整数N,M。2≤N≤500,1≤M≤20,000。

第2..M+1行:每行3个整数u,v,c(u,v),表示一条边(u,v)及其容量c(u,v)。1≤u,v≤N,0≤c(u,v)≤100。

给定的图中默认源点为1,汇点为N。可能有重复的边。

输出

第1行:2个整数A B,A表示最小割的容量,B表示给定图G最小割S集合的点数。

第2行:B个空格隔开的整数,表示S集合的点编号。

若存在多个最小割可以输出任意一个的解。

样例输入
6 7
1 2 3
1 3 5
2 4 1
3 4 2
3 5 3
4 6 4
5 6 2
样例输出
5 4
1 2 3 5

分析:题目中的S集合就是包含源点s的集合,先跑一遍最大流(dinic),求出残余网络再bfs分层,此时从源点能遍历到的点都是S集中的点,因为最小割的边一定是满流的,即残余流量为0。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define INF 999999999
using namespace std;
int map[502][502];
int N,M;
int dis[502],p[502];

int bfs()
{
    memset(dis,-1,sizeof(dis));
    dis[1]=0;
    queue<int> q;
    q.push(1);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=1;i<=N;i++)
        if(dis[i]==-1&&map[u][i]>0)
        {
            dis[i]=dis[u]+1;
            q.push(i);
        }
    }
    if(dis[N]>0) return 1;
    return 0;
}

int dfs(int cur,int m)
{
    if(cur==N) return m;
    int f,res=0;
    for(int i=1;i<=N;i++)
    {
        if(dis[i]==dis[cur]+1&&map[cur][i]>0&&(f=dfs(i,min(m,map[cur][i]))))
        {
            map[cur][i]-=f;
            map[i][cur]+=f;
            res+=f;
            m-=f;
            if(!m) break;
        }
    }
    if(res) return res;
    dis[cur]=-1;
    return 0;
}

int main()
{
    scanf("%d%d",&N,&M);
    for(int i=0;i<M;i++)
    {
        int s,t,c;
        scanf("%d%d%d",&s,&t,&c);
        map[s][t]+=c;
    }
    int ans=0,res;
    while(bfs())
        while(res=dfs(1,INF))
            ans+=res;
    int cnt=0;
    for(int i=1;i<=N;i++)
    if(dis[i]!=-1) p[cnt++]=i;
    printf("%d %d\n",ans,cnt);
    for(int i=0;i<cnt;i++) printf("%d ",p[i]);
    printf("\n");
    return 0;
}


原文地址:https://www.cnblogs.com/ACRykl/p/8858617.html

时间: 2024-10-06 06:51:39

hihoCoder1378 (最大流最小割)的相关文章

hihocoder 网络流二&#183;最大流最小割定理

网络流二·最大流最小割定理 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi:在上一周的Hiho一下中我们初步讲解了网络流的概念以及常规解法,小Ho你还记得内容么? 小Ho:我记得!网络流就是给定了一张图G=(V,E),以及源点s和汇点t.每一条边e(u,v)具有容量c(u,v).网络流的最大流问题求解的就是从s到t最多能有多少流量. 小Hi:那这个问题解决办法呢? 小Ho:解决网络流的基本思路就是寻找增广路,不断更新残留网络.直到找不到新的增广路,此时得到的

网络的最大流最小割定理

什么是流(flow): 在一个有向图中,只有出去的边没有进来的边的节点叫做源(source),只有进来的边没有出去的边的节点叫做汇(sink),其它的节点进来的边和出去的边应该是平衡的. 边上可以加权值,假设对于一个交通图来说,可以认为边上的权重为一条道路上的最大流量.那么对于图中任意两个节点来说,它们之间可以存在很多路径,每条路径上可以负载的最大流量应该是这条路径上权重最小的那条边所能承载的流量(联想一下“瓶颈”这个词,或者木桶理论),那么所有的路径上所负载流量之和也就是这两个节点之间多能通过

最大流最小割C++实现

最大流量问题:寻找从源点到汇点的最大流量. 使用最短增益路径法(或先标记先扫描法).这里标记意味着用两个记号来标记一个新的(为标记)的顶点:第一个标记指出从源点到被标记顶点还能增加多少流量:第二用来分别个标记指出另一个顶点的名字,就是从该顶点访问到被标记顶点的(对于源点来说这个标记可以不必指定).方便起见,也可以为第二个标记加上“+”或“-”符号,用来分别指出该顶点是通过前向边还是后向边访问到的.因此,源点可被标记为∞,-.对于其他顶点,按照以下方法计算它的标记: (1)如果为标记顶点j是由j到

【codevs1907】方格取数3(最大流最小割定理)

网址:http://codevs.cn/problem/1907/ 题意:在一个矩阵里选不相邻的若干个数,使这些数的和最大. 我们可以把它看成一个最小割,答案就是矩阵中的所有数-最小割.先把矩阵按国际象棋棋盘黑白染色(即把相邻的点分别染成白色和黑色),然后黑点连源点,白点连汇点.割掉一个点到源/汇的边就是不选择这个点,最后的目的就是使源到汇不连通(不引发题目不能选择位置相邻的数的矛盾). 然而最小割怎么求呢? 于是我们就要引入一个定理:最大流最小割定理.它的意思就是说,在一个图中,a点到b点的最

poj3469(最大流最小割问题)

题目链接:http://poj.org/problem?id=3469 Dual Core CPU Time Limit: 15000MS   Memory Limit: 131072K Total Submissions: 18147   Accepted: 7833 Case Time Limit: 5000MS Description As more and more computers are equipped with dual core CPU, SetagLilb, the Chi

最大流最小割一题

a 看完题目,根本没想法,暴力的复杂度是指数级别的,枚举所有的集合,当时有点紧张,暴力的都没写,其实没思路的 时候最好写暴力的算法,骗点分就可以了.后来,看了牛客网上大神的思路,然后学习了下最大流最小割的方法,这题的 做法就是枚举源点和汇点,跑最大流算法,然后用流量更新答案,同时保存最小割,最后输出,就可以了. 简单写了下,也是无法实际运行去判断正误. 对最大流最小割的思路理解的不是很透彻,不知道怎么求最小割,没有做这方面的练习. 1 #include <iostream> 2 #includ

最大流最小割算法

图像分割中用到最小割原理,引出了最大流最小割算法,主要参考来自UCLA CIVS的Hong Chen的PPT <Introduction to Min-Cut/Max-Flow Algorithms> 一. 首先借用PPT的两张图分别讲述一下两者的应用 1. 最大流应用于网络传输 2. 最小割应用于桥问题 二.基本概念之 s-t 图 1. 源结点(source node)和汇结点(sink node) 2. 从结点i到结点j的有向边(Arc)<i, j> 3. 每条边<i,

网络流(三)最大流最小割定理

转载:https://blog.csdn.net/w417950004/article/details/50538948 割(CUT)是网络中顶点的划分,它把网络中的所有顶点划分成两个顶点的集合源点S和汇点T.记为CUT(S,T). 如下图:源点:s=1;汇点:t=5.框外是容量,框内是流量 如下图是一个图的割.顶点集合S={1,2,3}和T={4,5}构成一个割. 如果一条弧的两个顶点分别属于顶点集S和T那么这条弧称为割CUT(S,T)的一条割边.  从S指向T的割边是正向割边,从T指向S的割

网络流基础-最大流最小割定理

最大流最小割定理,指网络流的最大流等于其最小割. 最大流指符合三个性质的前提下,从S到T能流过的最大流量. 最小割指符合割的定义,最小的割容量. 求最大流: 不断寻找增广路,计算能增加的最小流量,然后增加. 找到一条增光路,最多能流过2,则: 找到第二条路径: 最后还剩a-c-e一条,则可计算出最大流量为4. 但遇到以下情况,且第一条路径为a-b-c-d时,就不行了: 此时需要增加反向路径,即当减去增广路时,反向加上减去的流量,提供后悔的选择: 这样,当考虑a-c-b-d时,可以对冲掉b-c的流