Dinic PK Isap

  在Acm竞赛中,网络流中求最大流的主流算法有Dinic和Isap,那么这两种算法究竟选哪种好,有些人说Dinic稳定,有些人说Isap效率高,还有人说卡Dinic的题目都是不人道的。为此我分别测试了一下他们的效率。

  测试的题目是POJ3469,题目的测试数据足以分辨这两个算法的效率了,所提交的语言为G++。

  下面是Dinic的,没有加当前弧优化,用时5469ms。

Dinic-没有当前弧优化
  1 //STATUS:G++_AC_5469MS_8456KB

  2 #include<stdio.h>

  3 #include<stdlib.h>

  4 #include<string.h>

  5 #include<math.h>

  6 #include<iostream>

  7 #include<string>

  8 #include<algorithm>

  9 #include<vector>

 10 #include<queue>

 11 #include<stack>

 12 #include<map>

 13 using namespace std;

 14 #define LL long long

 15 #define Max(a,b) ((a)>(b)?(a):(b))

 16 #define Min(a,b) ((a)<(b)?(a):(b))

 17 #define mem(a,b) memset(a,b,sizeof(a))

 18 #define lson l,mid,rt<<1

 19 #define rson mid+1,r,rt<<1|1

 20 const int MAX=20010,INF=0x3f3f3f3f;

 21 

 22 struct Edge{

 23     int u,v,cap;

 24 }e[MAX*30];

 25 

 26 int first[MAX],next[MAX*30],d[MAX];

 27 int n,m,s,t,mm;

 28 

 29 void adde1(int a,int b,int val)

 30 {

 31     e[mm].u=a;e[mm].v=b;

 32     e[mm].cap=val;

 33     next[mm]=first[a];first[a]=mm++;

 34     e[mm].u=b;e[mm].v=a;

 35     e[mm].cap=0;

 36     next[mm]=first[b];first[b]=mm++;

 37 }

 38 

 39 void adde2(int a,int b,int val)

 40 {

 41     e[mm].u=a;e[mm].v=b;

 42     e[mm].cap=val;

 43     next[mm]=first[a];first[a]=mm++;

 44     e[mm].u=b;e[mm].v=a;

 45     e[mm].cap=val;

 46     next[mm]=first[b];first[b]=mm++;

 47 }

 48 

 49 int bfs()

 50 {

 51     int x,i,j;

 52     queue<int> q;

 53     mem(d,0);

 54     q.push(s);

 55     d[s]=1;

 56     while(!q.empty()){

 57         x=q.front();q.pop();

 58         for(i=first[x];i!=-1;i=next[i]){

 59             if(e[i].cap && !d[e[i].v]){

 60                 d[e[i].v]=d[x]+1;

 61                 q.push(e[i].v);

 62             }

 63         }

 64     }

 65     return d[t];

 66 }

 67 

 68 int dfs(int x,int a)

 69 {

 70     if(x==t || a==0)return a;

 71     int f,flow=0;

 72     for(int i=first[x];i!=-1;i=next[i]){

 73         if(d[x]+1==d[e[i].v] && (f=dfs(e[i].v,Min(a,e[i].cap)))){

 74             e[i].cap-=f;

 75             e[i^1].cap+=f;

 76             flow+=f;

 77             a-=f;

 78             if(!a)break;

 79         }

 80     }

 81     return flow;

 82 }

 83 

 84 int dinic()

 85 {

 86     int i,flow=0;

 87     while(bfs()){

 88         flow+=dfs(s,INF);

 89     }

 90     return flow;

 91 }

 92 

 93 int main()

 94 {

 95  //   freopen("in.txt","r",stdin);

 96     int i,a,b,val;

 97     while(~scanf("%d%d",&n,&m))

 98     {

 99         mm=0;

100         mem(first,-1);

101         s=0,t=n+1;

102         for(i=1;i<=n;i++){

103             scanf("%d%d",&a,&b);

104             adde1(s,i,a);

105             adde1(i,t,b);

106         }

107         for(i=0;i<m;i++){

108             scanf("%d%d%d",&a,&b,&val);

109             adde2(a,b,val);

110         }

111 

112         printf("%d\n",dinic());

113     }

114     return 0;

115 }

  然后是加了当前弧优化的Dinic,用时3891ms。

Dinic-有当前弧优化
  1 //STATUS:G++_AC_3891MS_8528KB

  2 #include<stdio.h>

  3 #include<stdlib.h>

  4 #include<string.h>

  5 #include<math.h>

  6 #include<iostream>

  7 #include<string>

  8 #include<algorithm>

  9 #include<vector>

 10 #include<queue>

 11 #include<stack>

 12 #include<map>

 13 using namespace std;

 14 #define LL long long

 15 #define Max(a,b) ((a)>(b)?(a):(b))

 16 #define Min(a,b) ((a)<(b)?(a):(b))

 17 #define mem(a,b) memset(a,b,sizeof(a))

 18 #define lson l,mid,rt<<1

 19 #define rson mid+1,r,rt<<1|1

 20 const int MAX=20010,INF=0x3f3f3f3f;

 21 

 22 struct Edge{

 23     int u,v,cap;

 24 }e[MAX*30];

 25 

 26 int first[MAX],next[MAX*30],d[MAX],cur[MAX];

 27 int n,m,s,t,mm;

 28 

 29 void adde1(int a,int b,int val)

 30 {

 31     e[mm].u=a;e[mm].v=b;

 32     e[mm].cap=val;

 33     next[mm]=first[a];first[a]=mm++;

 34     e[mm].u=b;e[mm].v=a;

 35     e[mm].cap=0;

 36     next[mm]=first[b];first[b]=mm++;

 37 }

 38 

 39 void adde2(int a,int b,int val)

 40 {

 41     e[mm].u=a;e[mm].v=b;

 42     e[mm].cap=val;

 43     next[mm]=first[a];first[a]=mm++;

 44     e[mm].u=b;e[mm].v=a;

 45     e[mm].cap=val;

 46     next[mm]=first[b];first[b]=mm++;

 47 }

 48 

 49 int bfs()

 50 {

 51     int x,i,j;

 52     queue<int> q;

 53     mem(d,0);

 54     q.push(s);

 55     d[s]=1;

 56     while(!q.empty()){

 57         x=q.front();q.pop();

 58         for(i=first[x];i!=-1;i=next[i]){

 59             if(e[i].cap && !d[e[i].v]){

 60                 d[e[i].v]=d[x]+1;

 61                 q.push(e[i].v);

 62             }

 63         }

 64     }

 65     return d[t];

 66 }

 67 

 68 int dfs(int x,int a)

 69 {

 70     if(x==t || a==0)return a;

 71     int f,flow=0;

 72     for(int& i=cur[x];i!=-1;i=next[i]){

 73         if(d[x]+1==d[e[i].v] && (f=dfs(e[i].v,Min(a,e[i].cap)))){

 74             e[i].cap-=f;

 75             e[i^1].cap+=f;

 76             flow+=f;

 77             a-=f;

 78             if(!a)break;

 79         }

 80     }

 81     return flow;

 82 }

 83 

 84 int dinic()

 85 {

 86     int i,flow=0;

 87     while(bfs()){

 88         for(i=0;i<=t;i++)cur[i]=first[i];

 89         flow+=dfs(s,INF);

 90     }

 91     return flow;

 92 }

 93 

 94 int main()

 95 {

 96  //   freopen("in.txt","r",stdin);

 97     int i,a,b,val;

 98     while(~scanf("%d%d",&n,&m))

 99     {

100         mm=0;

101         mem(first,-1);

102         s=0,t=n+1;

103         for(i=1;i<=n;i++){

104             scanf("%d%d",&a,&b);

105             adde1(s,i,a);

106             adde1(i,t,b);

107         }

108         for(i=0;i<m;i++){

109             scanf("%d%d%d",&a,&b,&val);

110             adde2(a,b,val);

111         }

112 

113         printf("%d\n",dinic());

114     }

115     return 0;

116 }

  这道题的时限是15000ms,从上面可以看出,一般来说,Dinic已经完全够用了,而且Dinic的代码量不大,敲起来速度快,逻辑结构清晰,所以Dinic在比赛中还是挺好用的。更要注意的是,当前弧优化是一定要加的,上面加了速度快了不少,而且好像有些题目就是专门卡这个,加了就能轻松AC,不加直接TLE!

  然后来看看Isap的效率。

  开始没有初始化距离数组d[]的Isap,用时2391ms。

Isap-没有初始化d[]
  1 //STATUS:G++_AC_2391MS_8592KB

  2 #include<stdio.h>

  3 #include<stdlib.h>

  4 #include<string.h>

  5 #include<math.h>

  6 #include<iostream>

  7 #include<string>

  8 #include<algorithm>

  9 #include<vector>

 10 #include<queue>

 11 #include<stack>

 12 #include<map>

 13 using namespace std;

 14 #define LL long long

 15 #define Max(a,b) ((a)>(b)?(a):(b))

 16 #define Min(a,b) ((a)<(b)?(a):(b))

 17 #define mem(a,b) memset(a,b,sizeof(a))

 18 #define lson l,mid,rt<<1

 19 #define rson mid+1,r,rt<<1|1

 20 const int MAX=20010,INF=0x3f3f3f3f;

 21 

 22 struct Edge{

 23     int u,v,cap;

 24 }e[MAX*30];

 25 

 26 int first[MAX],next[MAX*30],d[MAX],cur[MAX],fa[MAX],num[MAX];

 27 int n,m,s,t,mm;

 28 

 29 void adde1(int a,int b,int val)

 30 {

 31     e[mm].u=a;e[mm].v=b;

 32     e[mm].cap=val;

 33     next[mm]=first[a];first[a]=mm++;

 34     e[mm].u=b;e[mm].v=a;

 35     e[mm].cap=0;

 36     next[mm]=first[b];first[b]=mm++;

 37 }

 38 

 39 void adde2(int a,int b,int val)

 40 {

 41     e[mm].u=a;e[mm].v=b;

 42     e[mm].cap=val;

 43     next[mm]=first[a];first[a]=mm++;

 44     e[mm].u=b;e[mm].v=a;

 45     e[mm].cap=val;

 46     next[mm]=first[b];first[b]=mm++;

 47 }

 48 

 49 int augment()

 50 {

 51     int x=t,a=INF;

 52     while(x!=s){

 53         a=Min(a,e[fa[x]].cap);

 54         x=e[fa[x]].u;

 55     }

 56     x=t;

 57     while(x!=s){

 58         e[fa[x]].cap-=a;

 59         e[fa[x]^1].cap+=a;

 60         x=e[fa[x]].u;

 61     }

 62     return a;

 63 }

 64 

 65 int isap()

 66 {

 67     int i,x,ok,min,flow=0;

 68     mem(d,0);mem(num,0);

 69     num[0]=n;

 70     for(i=0;i<n;i++)cur[i]=first[i];

 71     x=s;

 72     while(d[s]<n){

 73         if(x==t){

 74             flow+=augment();

 75             x=s;

 76         }

 77         ok=0;

 78         for(i=cur[x];i!=-1;i=next[i]){

 79             if(e[i].cap && d[x]==d[e[i].v]+1){

 80                 ok=1;

 81                 fa[e[i].v]=i;

 82                 cur[x]=i;

 83                 x=e[i].v;

 84                 break;

 85             }

 86         }

 87         if(!ok){

 88             min=n-1;

 89             for(i=first[x];i!=-1;i=next[i])

 90                 if(e[i].cap && d[e[i].v]<min)min=d[e[i].v];

 91             if(--num[d[x]]==0)break;

 92             num[d[x]=min+1]++;

 93             cur[x]=first[x];

 94             if(x!=s)x=e[fa[x]].u;

 95         }

 96     }

 97     return flow;

 98 }

 99 

100 int main()

101 {

102  //   freopen("in.txt","r",stdin);

103     int i,a,b,val;

104     while(~scanf("%d%d",&n,&m))

105     {

106         mm=0;

107         mem(first,-1);

108         s=0,t=n+1;

109         for(i=1;i<=n;i++){

110             scanf("%d%d",&a,&b);

111             adde1(s,i,a);

112             adde1(i,t,b);

113         }

114         for(i=0;i<m;i++){

115             scanf("%d%d%d",&a,&b,&val);

116             adde2(a,b,val);

117         }

118 

119         n+=2;

120         printf("%d\n",isap());

121     }

122     return 0;

123 }

  用bfs初始化距离数组d[]的Isap,用时2454ms。

Isap-初始化了d[]
  1 //STATUS:G++_AC_2454MS_8684KB

  2 #include<stdio.h>

  3 #include<stdlib.h>

  4 #include<string.h>

  5 #include<math.h>

  6 #include<iostream>

  7 #include<string>

  8 #include<algorithm>

  9 #include<vector>

 10 #include<queue>

 11 #include<stack>

 12 #include<map>

 13 using namespace std;

 14 #define LL long long

 15 #define Max(a,b) ((a)>(b)?(a):(b))

 16 #define Min(a,b) ((a)<(b)?(a):(b))

 17 #define mem(a,b) memset(a,b,sizeof(a))

 18 #define lson l,mid,rt<<1

 19 #define rson mid+1,r,rt<<1|1

 20 const int MAX=20010,INF=0x3f3f3f3f;

 21 

 22 struct Edge{

 23     int u,v,cap;

 24 }e[MAX*30];

 25 

 26 int first[MAX],next[MAX*30],d[MAX],cur[MAX],fa[MAX],num[MAX];

 27 int n,m,s,t,mm;

 28 

 29 void adde1(int a,int b,int val)

 30 {

 31     e[mm].u=a;e[mm].v=b;

 32     e[mm].cap=val;

 33     next[mm]=first[a];first[a]=mm++;

 34     e[mm].u=b;e[mm].v=a;

 35     e[mm].cap=0;

 36     next[mm]=first[b];first[b]=mm++;

 37 }

 38 

 39 void adde2(int a,int b,int val)

 40 {

 41     e[mm].u=a;e[mm].v=b;

 42     e[mm].cap=val;

 43     next[mm]=first[a];first[a]=mm++;

 44     e[mm].u=b;e[mm].v=a;

 45     e[mm].cap=val;

 46     next[mm]=first[b];first[b]=mm++;

 47 }

 48 

 49 void bfs()

 50 {

 51     int x,i,j;

 52     queue<int> q;

 53     mem(d,-1);

 54     q.push(t);

 55     d[t]=0;

 56     while(!q.empty()){

 57         x=q.front();q.pop();

 58         for(i=first[x];i!=-1;i=next[i]){

 59             if(d[e[i].v]<0){

 60                 d[e[i].v]=d[x]+1;

 61                 q.push(e[i].v);

 62             }

 63         }

 64     }

 65 }

 66 

 67 int augment()

 68 {

 69     int x=t,a=INF;

 70     while(x!=s){

 71         a=Min(a,e[fa[x]].cap);

 72         x=e[fa[x]].u;

 73     }

 74     x=t;

 75     while(x!=s){

 76         e[fa[x]].cap-=a;

 77         e[fa[x]^1].cap+=a;

 78         x=e[fa[x]].u;

 79     }

 80     return a;

 81 }

 82 

 83 int isap()

 84 {

 85     int i,x,ok,min,flow=0;

 86     mem(num,0);

 87     bfs();

 88     for(i=0;i<n;i++)num[d[i]]++;

 89     for(i=0;i<n;i++)cur[i]=first[i];

 90     x=s;

 91     while(d[s]<n){

 92         if(x==t){

 93             flow+=augment();

 94             x=s;

 95         }

 96         ok=0;

 97         for(i=cur[x];i!=-1;i=next[i]){

 98             if(e[i].cap && d[x]==d[e[i].v]+1){

 99                 ok=1;

100                 fa[e[i].v]=i;

101                 cur[x]=i;

102                 x=e[i].v;

103                 break;

104             }

105         }

106         if(!ok){

107             min=n-1;

108             for(i=first[x];i!=-1;i=next[i])

109                 if(e[i].cap && d[e[i].v]<min)min=d[e[i].v];

110             if(--num[d[x]]==0)break;

111             num[d[x]=min+1]++;

112             cur[x]=first[x];

113             if(x!=s)x=e[fa[x]].u;

114         }

115     }

116     return flow;

117 }

118 

119 int main()

120 {

121  //   freopen("in.txt","r",stdin);

122     int i,a,b,val;

123     while(~scanf("%d%d",&n,&m))

124     {

125         mm=0;

126         mem(first,-1);

127         s=0,t=n+1;

128         for(i=1;i<=n;i++){

129             scanf("%d%d",&a,&b);

130             adde1(s,i,a);

131             adde1(i,t,b);

132         }

133         for(i=0;i<m;i++){

134             scanf("%d%d%d",&a,&b,&val);

135             adde2(a,b,val);

136         }

137 

138         n+=2;

139         printf("%d\n",isap());

140     }

141     return 0;

142 }

  发现Isap的效率比Dinic的效率是快了一倍样子!果然当前弧优化+距离标号的算法效率很高,而且没有初始化距离数组的d[]的Isap代码也很短,性价比非常高。至于初始化了距离数组d[]的Isap虽然最求一次最大流效率没怎么改变,但是如果是多次求解规模较小的网络流是,效率还是会有明显提升的。

  其实我觉得Dinic无论从那个方面来讲,都是劣于Isap的,从时间效率上来讲,Isap快于Dinic,从代码上来讲,Isap和Dnic还是差不了多少,甚至我觉得Isap写起来还要短些,而且更为重要的是Isap可以直接一个循环结构搞定,而Dinic的递归写起来虽然方便,但某些时候可能会遇到爆栈的情况,如果写成迭代形式的Dinic就还需要维护一个栈,相对起来又麻烦些。所以,我们没有理由不用Isap,至于有人说Dinic更稳定,以后有待验证!

 

 

 

你可能感兴趣的:(dinic)