您的位置:首页 > 其它

证明增广路算法的正确性及dinic算法的使用

2016-07-28 19:11 483 查看
一直对增广路这种贪心思想表示怀疑,今天看到一个很好的证明。

首先介绍割的概念,所谓图的割,指的是某个顶点集合S属于V,从S出发的所有边的集合成为割(S,V\S),这些边的容量和被称为割的容量,如果有源点s属于S,汇点t属于V\S,则称之为s-t割,如果将s-t割的所有边都在原图中去掉,则不再有s->t的路径。

容易得到,对于任意一个s-t割,总有f的流量<=割的容量,根据平衡条件,当且仅当割为最小割,流为最大流时去等号

首先,对于ford-Fulkerson算法求出的流为f,f对应的残余网络中从s可达的顶点集合为S,因为f对应的残余网络中不存在从s->t的路径了,那么显然,在残余网络中,任意一条从S->

V\S 中的边流量f=c,任意一条从反向弧f=0,这个一定是满足,如果不满足,那么S集合还可以扩充顶点,与前提矛盾。因此,S->V\S的割的容量等于流的大小。则可以证明裸的増广路ford算法是正确的。

再说一下dinic算法,dinic算法总是寻找最短的増广路并沿着它增广,増广路的长度不会在增广过程中改变,则当无法增广时,说明分层图上没有可以增广的路线了,这有两种情况,第一,已经求出了最大流,第二,可能存在长一些的増广路可以继续增广,因此,继续bfs构造分层网络。每次完成后最短増广路长度+1,由于最短路<n,则最对重复n-1次bfs就可完成了。

#include <queue>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int max_node = 20;
const int INF = 0x3f3f3f3f;
struct Edge{
int to,cap,rev;
Edge(int t,int c,int r):to(t),cap(c),rev(r) {}
};
vector<Edge> G[max_node];
int node_num,edge_num;
int dis[max_node]; //各顶点到源点的无权距离,通过BFS得到
int cur[max_node]; //当前弧优化

void push_edge(int from,int to,int cap){ //直接建立残余网络,插入反向边的方式很巧妙
G[from].push_back( Edge(to,cap,G[to].size()) );
G[to].push_back( Edge(from,0,G[from].size()-1) );
}

void BFS(){
memset(dis, -1, sizeof(dis));
dis[1]=0;
queue<int> q;
q.push(1);
while(!q.empty()){
int t = q.front(); q.pop();
for(int k = 0; k < G[t].size(); k++){
Edge &e = G[t][k];
if(e.cap > 0 && dis[e.to] == -1){ // 沿着残余网络进行标记
dis[e.to] = dis[t] + 1;
q.push(e.to);
}
}
}
}

int DFS(int u, int v, int res){
if( u == v) return res;
for(int k = cur[u]; k < G[u].size(); k++){
int to = G[u][k].to;
if( G[u][k].cap > 0 && dis[to] == dis[u] + 1){ //沿着残余网络深度优先搜索
int x = DFS(to, v, min(res, G[u][k].cap));
if(x > 0){
G[u][k].cap -= x;
int rev = G[u][k].rev;
G[to][rev].cap += x;
cur[u] = k;
return x;
}
}
}
return 0;
}

int maxFlow(){
int flow = 0;
while(1)
{
memset(cur, 0, sizeof(cur)); //当前弧自然从0开始
BFS(); //构造分层图
if(dis[node_num] == -1){ //最小割出现,找不到增广路
return flow;
}
//在当前分层图上进行最短路增广,如果无法继续增广,则说明当前分层图不存在增广路了,需要重新构造更长路径的分层图
while( int x = DFS(1, node_num, INF) ){
flow += x;
}
}
}

int main(){
#ifdef LOCAL_DEBUG
freopen("input.txt" ,"r", stdin);
#endif // LOCAL_DEBUG
int T,cas=1;
scanf("%d" ,&T);
while(T--){
printf("Case %d: ",cas++);
for(int i=0; i<max_node; i++) G[i].clear();
node_num = edge_num = 0;
scanf("%d%d" ,&node_num, &edge_num);
int from, to, cap;
for(int i=1; i<=edge_num; i++){
scanf("%d%d%d" ,&from ,&to, &cap);
push_edge(from, to, cap);
}
printf("%d\n" ,maxFlow());
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: