Dinic算法

        Dinic算法(又称Dinitz算法)是一个在网络流中计算最大流的多项式复杂度的算法,设想由以色列(前苏联)的计算机科学家Yefim (Chaim) A. Dinitz在1970年提出。 最短增广路EK算法每次BFS找到一条增广路,增流后,需要重新BFS找下一条增广路,直到找不到增广路为止。

        Dinic算法,首先从源点出发BFS分“层”,然后从源点出发DFS,沿着d[y]=d[x]+1的边(x,y)找增广路,一次DFS可以实现多次增广,这正是Dinic算法的巧妙之处。

        算法步骤:

        1)在残余网络上BFS构造分层图;

        2)在层次图中DFS找增广路,进行增流,直到不存在增广路。

        3)重复以上步骤直到无法增广。

        例如,网络流的残余网络如图所示。

        11c3b016ede741c49ac36c1f4046c3b4.png

        28011e6186d5494fa3bdbc9269af7630.png 

        d6cc7c7265874b32bfd490403e5d4307.png 

e5e10244b8804502bf2e3cd9a9fbb5d0.png 

6c555e68d65c4821a1ac19a6acedada5.png 

67701d696ec5400091edad7988b70c74.png 

        因为在Dinic的执行过程中,每次重新分层,汇点所在的层次是严格递增的,而V个点的层次图最多有V层,所以最多重新分层V次。在同一个层次图中,因为每条增广路都有一个瓶颈,而两次增广的瓶颈不可能相同,所以增广路最多E条。搜索每一条增广路时,前进和回溯都最多V次,所以这两者造成的时间复杂度是O(VE);而沿着同一条边(i,j)不可能枚举两次,因为第一次枚举时要么这条边的容量已经用尽,要么点j到汇不存在通路从而可将其从这一层次图中删除。综上所述,Dinic算法时间复杂度的理论上界是O(V2E)。Dinic算法一般可以处理104~105规模的网络。

        

#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=100;
const int M=10000;
int cnt,n,m;
int head[N],d[N];
struct Edge{
   int v,next;
   int cap,flow;
}E[M];

void init(){//初始化 
    memset(head,-1,sizeof(head));
    cnt=0;
}

void add(int u,int v,int c){
    E[cnt].v=v;
    E[cnt].cap=c;
    E[cnt].flow=0;
    E[cnt].next=head[u];
    head[u]=cnt++;
}

bool bfs(int s,int t){//分层
    memset(d,0,sizeof(d));
    queue<int>q;
    d[s]=1;
    q.push(s);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head[u];~i;i=E[i].next){
        	int v=E[i].v;
        	if(!d[v]&&E[i].cap>E[i].flow){
                d[v]=d[u]+1;
				q.push(v);
				if(v==t)  return 1;
			}	
		}
    }
    return 0;
}

int dfs(int u,int flow,int t){//在分层的基础上dfs 
    if(u==t) return flow;
	int rest=flow;//可增量 
    for(int i=head[u];~i&&rest;i=E[i].next){
    	int v=E[i].v;
    	if(d[v]==d[u]+1&&E[i].cap>E[i].flow){
            int k=dfs(v,min(rest,E[i].cap-E[i].flow),t);
			if(!k) d[v]=0,cout<<"d["<<v<<"]="<<d[v]<<endl;
			E[i].flow+=k;
			E[i^1].flow-=k;
			rest-=k;
			cout<<u<<"--"<<v<<"增流 k="<<k<<endl;
		}	
	}
	return flow-rest;
}

int Dinic(int s,int t){
	int maxflow=0;
	while(bfs(s,t)){
		for(int i=1;i<=n;i++)
			cout<<"d["<<i<<"]="<<d[i]<<endl;
		maxflow+=dfs(s,inf,t);
		cout<<"增流后:"<<maxflow<<endl;
	}
	return maxflow;
}

void printg(){//输出网络
	cout<<endl;
	cout<<"----------网络(链式前向星):----------"<<endl;
	for(int i=1;i<=n;i++){
		cout<<"v"<<i<<"  ["<<head[i];
		for(int j=head[i];~j;j=E[j].next)
			cout<<"]--["<<E[j].v<<"\t"<<E[j].cap<<"\t"<<E[j].flow<<"\t"<<E[j].next;
		cout<<"]"<<endl;
   }
   cout<<endl;
}

void printflow(){//输出实流边
	cout<<endl;
	cout<<"----------实流边:----------"<<endl;
	for(int i=1;i<=n;i++)
		for(int j=head[i];~j;j=E[j].next)
			if(E[j].flow>0){
				cout<<"v"<<i<<"--"<<"v"<<E[j].v<<"\t"<<E[j].flow;
				cout<<endl;
        	}
}
/*
请输入结点个数n和边数m:
6 9
1 3 15
1 2 10
2 5 4
2 4 8
3 5 13
3 2 2
4 6 18
5 6 9
5 4 6
*/
int main(){
    int u,v,w;
    cout<<"请输入结点个数n和边数m:"<<endl;
    cin>>n>>m;
    init();
    cout<<"请输入两个结点u,v及边(u--v)的容量w:"<<endl;
    for(int i=1;i<=m;i++){
        cin>>u>>v>>w;
        add(u,v,w);
		add(v,u,0);
    }
    printg();//输出初始网络
    cout<<"最大流值:"<<Dinic(1,n)<<endl;
    printg();//输出最终网络
    printflow();//输出实流边
    return 0;
}

 

P3376
#include<cstdio>//81ms,加当前弧优化51ms,不加任何优化超时  
#include<cstring>
#include<queue>
#include<algorithm>
#define ll long long
const int inf=0x3f3f3f3f;
const int N=210;
const int M=5010;
using namespace std;
struct newt{
	int v,w,next;
}E[M<<1];
int head[N],d[N],n,m,s,t,cnt;

void init(){//初始化 
    memset(head,-1,sizeof(head));
    cnt=0;
}

void adde(int u,int v,int w){
	E[cnt].v=v;
	E[cnt].w=w;
	E[cnt].next=head[u];
	head[u]=cnt++;
}
 
bool bfs(){//分层
    memset(d,0,sizeof(d));
    queue<int>q;
    d[s]=1;
    q.push(s);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head[u];~i;i=E[i].next){
        	int v=E[i].v;
        	if(!d[v]&&E[i].w>0){
                d[v]=d[u]+1;
				q.push(v);
				if(v==t)  return 1;
			}	
		}
    }
    return 0;
}

int dfs(int u,int flow){//在分层的基础上dfs 
    if(u==t) return flow;
	int rest=flow;//最小残量 
    for(int i=head[u];~i&&rest;i=E[i].next){
    	int v=E[i].v;
    	if(d[v]==d[u]+1&&E[i].w>0){
            int k=dfs(v,min(rest,E[i].w));
			if(!k) d[v]=0;//优化阻断,不加超时 
			E[i].w-=k;
			E[i^1].w+=k;
			rest-=k;
		}	
	}
	return flow-rest;
}

ll Dinic(int s,int t){
	ll maxflow=0;
	while(bfs()){
		maxflow+=dfs(s,inf);
	}
	return maxflow;
}

int main(){
	int u,v,w;
	while(~scanf("%d%d%d%d",&n,&m,&s,&t)){
        init();
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&u,&v,&w);
            adde(u,v,w),adde(v,u,0);
        }
        printf("%lld\n", Dinic(s,t));
    }
	return 0;
}
P3376优化
#include<cstdio>//当前弧优化51ms 
#include<cstring>
#include<queue>
#include<algorithm>
#define ll long long
const int inf=0x3f3f3f3f;
const int N=210;
const int M=5010;
using namespace std;
struct newt{
	int v,w,next;
}E[M<<1];
int head[N],cur[N],d[N],n,m,s,t,cnt;

void init(){//初始化 
    memset(head,-1,sizeof(head));
    cnt=0;
}

void adde(int u,int v,int w){
	E[cnt].v=v;
	E[cnt].w=w;
	E[cnt].next=head[u];
	head[u]=cnt++;
}
 
bool bfs(){//分层
    memset(d,0,sizeof(d));
    queue<int>q;
    d[s]=1;
    q.push(s);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head[u];~i;i=E[i].next){
        	int v=E[i].v;
        	if(!d[v]&&E[i].w>0){
                d[v]=d[u]+1;
				q.push(v);
				if(v==t)  return 1;
			}	
		}
    }
    return 0;
}

int dfs(int u,int flow){//在分层的基础上dfs 
    if(u==t) return flow;
	int rest=flow;//最小残量 
    for(int &i=cur[u];~i;i=E[i].next){//引用&,cur和i一起更新,或在内部写cur[u]=E[i].next 
    	int v=E[i].v;
    	if(d[v]==d[u]+1&&E[i].w>0){
            int k=dfs(v,min(rest,E[i].w));
			if(!k) d[v]=0;//优化,有当前弧优化时,去掉也没影响 
			E[i].w-=k;
			E[i^1].w+=k;
			rest-=k;
			if(!rest) break;
		}	
	}
	return flow-rest;
}

ll Dinic(int s,int t){
	ll maxflow=0;
	while(bfs()){
		for(int i=1;i<=n;i++)
			cur[i]=head[i];
		maxflow+=dfs(s,inf);
	}
	return maxflow;
}

int main(){
	int u,v,w;
	while(~scanf("%d%d%d%d",&n,&m,&s,&t)){
        init();
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&u,&v,&w);
            adde(u,v,w),adde(v,u,0);
        }
        printf("%lld\n", Dinic(s,t));
    }
	return 0;
}
poj1149
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=110;
const int M=10100;
int cnt;
int head[N],d[N],a[1010],belong[1010];
struct Edge{
   int v,next;
   int cap,flow;
}E[M<<1];//双边

void init(){//初始化 
    memset(head,-1,sizeof(head));
    cnt=0;
}

void add(int u,int v,int c){
    E[cnt].v=v;
    E[cnt].cap=c;
    E[cnt].flow=0;
    E[cnt].next=head[u];
    head[u]=cnt++;
}

void adde(int u,int v,int c){
    add(u,v,c);
    add(v,u,0);
}

bool bfs(int s,int t){//分层
    memset(d,0,sizeof(d));
    queue<int>q;
    d[s]=1;
    q.push(s);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head[u];~i;i=E[i].next){
        	int v=E[i].v;
        	if(!d[v]&&E[i].cap>E[i].flow){
                d[v]=d[u]+1;
				q.push(v);
				if(v==t)  return 1;
			}	
		}
    }
    return 0;
}

int dfs(int u,int flow,int t){//在分层的基础上dfs 
    if(u==t) return flow;
	int rest=flow;
    for(int i=head[u];~i&&rest;i=E[i].next){
    	int v=E[i].v;
    	if(d[v]==d[u]+1&&E[i].cap>E[i].flow){
            int k=dfs(v,min(rest,E[i].cap-E[i].flow),t);
			if(!k) d[v]=0;
			E[i].flow+=k;
			E[i^1].flow-=k;
			rest-=k;
		}	
	}
	return flow-rest;
}

int Dinic(int s,int t){
	int maxflow=0;
	while(bfs(s,t)){
		maxflow+=dfs(s,inf,t);
	}
	return maxflow;
}

int main(){
    int m,n,k,x,w,d;
    scanf("%d%d",&m,&n);
    init();
    for(int i=1;i<=m;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;i++){//n个客户 
        scanf("%d",&k);//钥匙数 
        w=0;
        for(int j=1;j<=k;j++){
            scanf("%d",&x);
            if(belong[x]==0) 
                w+=a[x];
            else
                adde(belong[x],i,inf);
            belong[x]=i;//标记最近打开x猪圈的客户编号
        }
        adde(0,i,w);
        scanf("%d",&d);
        adde(i,n+1,d);
    }
    printf("%d\n",Dinic(0,n+1));
    return 0; 
}
poj1459
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=110;
const int M=10100;
int cnt;
int head[N],d[N];
struct Edge{
   int v,next;
   int cap,flow;
}E[M<<1];//双边

void init(){//初始化 
    memset(head,-1,sizeof(head));
    cnt=0;
}

void add(int u,int v,int c){
    E[cnt].v=v;
    E[cnt].cap=c;
    E[cnt].flow=0;
    E[cnt].next=head[u];
    head[u]=cnt++;
}

void adde(int u,int v,int c){
    add(u,v,c);
    add(v,u,0);
}

bool bfs(int s,int t){//分层
    memset(d,0,sizeof(d));
    queue<int>q;
    d[s]=1;
    q.push(s);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head[u];~i;i=E[i].next){
        	int v=E[i].v;
        	if(!d[v]&&E[i].cap>E[i].flow){
                d[v]=d[u]+1;
				q.push(v);
				if(v==t)  return 1;
			}	
		}
    }
    return 0;
}

int dfs(int u,int flow,int t){//在分层的基础上dfs 
    if(u==t) return flow;
	int rest=flow;
    for(int i=head[u];~i&&rest;i=E[i].next){
    	int v=E[i].v;
    	if(d[v]==d[u]+1&&E[i].cap>E[i].flow){
            int k=dfs(v,min(rest,E[i].cap-E[i].flow),t);
			if(!k) d[v]=0;//没有这行优化,1625ms,优化后485ms
			E[i].flow+=k;
			E[i^1].flow-=k;
			rest-=k;
		}	
	}
	return flow-rest;
}

int Dinic(int s,int t){
	int maxflow=0;
	while(bfs(s,t)){
		maxflow+=dfs(s,inf,t);
	}
	return maxflow;
}

int main(){
    int n,np,nc,m,u,v,w;
	char ch;
    while(cin>>n>>np>>nc>>m){
        init();
        for(int i=1;i<=m;i++){
			cin>>ch>>u>>ch>>v>>ch>>w;
            adde(u,v,w);
        }
        for(int i=1;i<=np;i++){
			cin>>ch>>v>>ch>>w;
            adde(n+1,v,w);
        }
        for(int i=1;i<=nc;i++){
            cin>>ch>>u>>ch>>w;
            adde(u,n+2,w);
        }
        cout<<Dinic(n+1,n+2)<<endl;
    }
    return 0;
}
poj1459优化
#include<iostream>//当前弧优化,下次直接从cur[u]开始增广,节省时间
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=110;
const int M=10100;
int n,m,cnt;
int head[N],d[N],cur[N];
struct Edge{
   int v,next;
   int cap,flow;
}E[M<<1];//双边

void init(){//初始化 
    memset(head,-1,sizeof(head));
    cnt=0;
}

void add(int u,int v,int c){
    E[cnt].v=v;
    E[cnt].cap=c;
    E[cnt].flow=0;
    E[cnt].next=head[u];
    head[u]=cnt++;
}

void adde(int u,int v,int c){
    add(u,v,c);
    add(v,u,0);
}

bool bfs(int s,int t){//分层
    memset(d,0,sizeof(d));
    queue<int>q;
    d[s]=1;
    q.push(s);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head[u];~i;i=E[i].next){
        	int v=E[i].v;
        	if(!d[v]&&E[i].cap>E[i].flow){
                d[v]=d[u]+1;
				q.push(v);
				if(v==t)  return 1;
			}	
		}
    }
    return 0;
}

int dfs(int u,int flow,int t){//在分层的基础上dfs 
    if(u==t) return flow;
	int rest=flow;//可增量 
    for(int &i=cur[u];~i;i=E[i].next){//引用&,cur和i一起更新,或在内部写cur[u]=E[i].next 
    	int v=E[i].v;
    	if(d[v]==d[u]+1&&E[i].cap>E[i].flow){
            int k=dfs(v,min(rest,E[i].cap-E[i].flow),t);
			if(!k) d[v]=0;//优化
			E[i].flow+=k;
			E[i^1].flow-=k;
			rest-=k;
			if(!rest) break;//此处很重要,避免更新cur
		}	
	}
	return flow-rest;
}

int Dinic(int s,int t){
	int maxflow=0;
	while(bfs(s,t)){
		for(int i=0;i<=n+2;i++)
			cur[i]=head[i];
		maxflow+=dfs(s,inf,t);
	}
	return maxflow;
}

int main(){
    int np,nc,u,v,w;
	char ch;
    while(cin>>n>>np>>nc>>m){
        init();
        for(int i=1;i<=m;i++){
			cin>>ch>>u>>ch>>v>>ch>>w;
            adde(u,v,w);
        }
        for(int i=1;i<=np;i++){
			cin>>ch>>v>>ch>>w;
            adde(n+1,v,w);
        }
        for(int i=1;i<=nc;i++){
            cin>>ch>>u>>ch>>w;
            adde(u,n+2,w);
        }
        cout<<Dinic(n+1,n+2)<<endl;
    }
    return 0;
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值