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)重复以上步骤直到无法增广。
例如,网络流的残余网络如图所示。
因为在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;
}