• 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更稳定,以后有待验证!

  • 相关阅读:
    C# Winform下一个热插拔的MIS/MRP/ERP框架(通用控件)
    Xamarin如何使用终端设备的NFC功能传递卡号等信息给Web页面(Android)
    C# Winform下一个热插拔的MIS/MRP/ERP框架(简介)
    C# Winform中自定义筛选及自带统计行的Datagridview控件
    C#下Excel的普通处理和报表设计
    JVM 垃圾回收算法
    谈数据库的性能优化
    RedisService
    bean 与 map 互转.
    RedisService
  • 原文地址:https://www.cnblogs.com/zhsl/p/2800092.html
Copyright © 2020-2023  润新知