zoukankan      html  css  js  c++  java
  • 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更稳定,以后有待验证!

  • 相关阅读:
    TCP源码—连接建立
    TCP系列02—连接管理—1、三次握手与四次挥手
    TCP系列01—概述及协议头格式
    ubuntu软件管理apt与dpkg
    318. Maximum Product of Word Lengths
    317. Shortest Distance from All Buildings
    316. Remove Duplicate Letters
    315. Count of Smaller Numbers After Self
    314. Binary Tree Vertical Order Traversal
    313. Super Ugly Number
  • 原文地址:https://www.cnblogs.com/zhsl/p/2800092.html
Copyright © 2011-2022 走看看