最大流模板

AC HDU 3061 一道最大权闭合子图裸题

以前写的DINIC太慢了啊TAT

老T.....

这个DINIC加了俩优化.......

  • 当前弧优化.在一次增广中,我们总是从某个节点一条弧一条弧地放流,也就是说我们依次把弧塞满....

   把某条弧塞满以后接下来的DFS过程中就不需要再遍历这条弧了.......

   那我可以通过修改边表避免以后再遍历这些满弧........

  • 考虑广搜的时候,找到了汇点并给它标上深度,那么就可以直接跳出广搜了.

   因为在这以后标深度的节点都不能走向汇(因为它们的深度大于等于汇点深度),就是说从那些节点不会有可行流.

 

  1 #include <cstdio>
  2 #include <fstream>
  3 #include <iostream>
  4  
  5 #include <cstdlib>
  6 #include <cstring>
  7 #include <algorithm>
  8 #include <cmath>
  9  
 10 #include <queue>
 11 #include <vector>
 12 #include <map>
 13 #include <set>
 14 #include <stack>
 15 #include <list>
 16  
 17 typedef unsigned int uint;
 18 typedef long long int ll;
 19 typedef unsigned long long int ull;
 20 typedef double db;
 21  
 22 using namespace std;
 23  
 24 inline int getint()
 25 {
 26     int res=0;
 27     char c=getchar();
 28     bool mi=false;
 29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
 30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 31     return mi ? -res : res;
 32 }
 33 inline ll getll()
 34 {
 35     ll res=0;
 36     char c=getchar();
 37     bool mi=false;
 38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
 39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 40     return mi ? -res : res;
 41 }
 42  
 43 db eps=1e-20;
 44 inline bool feq(db a,db b)
 45 { return fabs(a-b)<eps; }
 46 
 47 template<typename Type>
 48 inline Type avg(const Type a,const Type b)
 49 { return a+((b-a)/2); }
 50 
 51 //==============================================================================
 52 //==============================================================================
 53 //==============================================================================
 54 //==============================================================================
 55 
 56 
 57 const int INF=(1<<30)-1;
 58 
 59 struct edge
 60 {
 61     int c;
 62     int in;
 63     edge*nxt;
 64     edge*ptr;
 65 }pool[205000];
 66 edge*et;
 67 edge*eds[1050];
 68 edge*cur[1050];
 69 edge*addedge(int i,int j,int c)
 70 {
 71     et->ptr=et+1;
 72     et->in=j; et->c=c; et->nxt=eds[i]; eds[i]=et++;
 73     et->ptr=et-1;
 74     et->in=i; et->c=0; et->nxt=eds[j]; eds[j]=et++; 
 75 }
 76 
 77 int n;
 78 int st,ed;
 79 int dep[1050];
 80 int DFS(int x,int mi)
 81 {
 82     if(x==ed) return mi;
 83     int res=0,c;
 84     for(edge*&i=cur[x];i;i=i->nxt)
 85     if(i->c>0 && dep[i->in]==dep[x]+1 && ( c=DFS(i->in,min(i->c,mi)) ))
 86     {
 87         i->c-=c;
 88         i->ptr->c+=c;
 89         res+=c;
 90         mi-=c;
 91         if(!mi) break;
 92     }
 93     if(!res) dep[x]=-1;
 94     return res;
 95 }
 96 
 97 int qh,qt;
 98 int q[1050];
 99 int DINIC()
100 {
101     int res=0;
102     
103     while(true)
104     {
105         memset(dep,0xFF,sizeof(int)*(n+1));
106         
107         qh=qt=0;
108         q[qt++]=st;
109         dep[st]=0;
110         bool found=false;
111         while(qh!=qt && !found)
112         {
113             int x=q[qh];
114             for(edge*i=eds[x];i && !found;i=i->nxt)
115             if(i->c>0 && dep[i->in]==-1)
116             {
117                 dep[i->in]=dep[x]+1;
118                 if(i->in==ed) { found=true; break; } 
119                 q[qt++]=i->in;
120             }
121             qh++;
122         }
123         
124         if(dep[ed]==-1) break;
125         
126         memcpy(cur,eds,sizeof(edge*)*(n+1));
127         res+=DFS(st,INF);
128     }
129     
130     return res;
131 }
132 
133 
134 int ntot,mtot;
135 
136 
137 
138 int main()
139 {
140     while(scanf("%d%d",&ntot,&mtot)>0)
141     {
142         st=ntot;
143         ed=st+1;
144         n=ed+1;
145         
146         et=pool;
147         memset(eds,0,sizeof(edge*)*(n+1));
148         
149         int sum=0;
150         
151         for(int i=0;i<ntot;i++)
152         {
153             int c=getint();
154             if(c>0) addedge(st,i,c),sum+=c;
155             else if(c<0) addedge(i,ed,-c);
156         }
157         
158         for(int i=0;i<mtot;i++)
159         {
160             int a,b;
161             a=getint()-1;
162             b=getint()-1;
163             addedge(a,b,INF);
164         }
165         
166         printf("%d\n",sum-DINIC());
167         
168     }
169     
170     return 0;
171 }
View Code

 

耗时390ms,还看得过眼.......

打一个DINIC预计时间10min左右....

 


 

 AC VIJOS P1590

  1 #include <cstdio>
  2 #include <fstream>
  3 #include <iostream>
  4 
  5 #include <cstdlib>
  6 #include <cstring>
  7 #include <algorithm>
  8 #include <cmath>
  9 
 10 #include <queue>
 11 #include <vector>
 12 #include <map>
 13 #include <set>
 14 #include <stack>
 15 
 16 typedef unsigned int uint;
 17 typedef long long int ll;
 18 typedef unsigned long long int ull;
 19 typedef double db;
 20 
 21 #define DBG printf("*")
 22 
 23 using namespace std;
 24 
 25 const int INF=(1<<28)-1;
 26 const ll LINF=((ll)1<<52)-1;
 27 
 28 struct edge
 29 {
 30     int in;
 31     ll c;
 32     edge*nxt;
 33     edge*ptr;
 34 }pool[100000];
 35 edge*et=pool;
 36 edge*eds[200];
 37 void addedge(int i,int j,ll c)
 38 {
 39     et->ptr=et+1;
 40     et->c=c; et->in=j; et->nxt=eds[i]; eds[i]=et++;
 41     et->ptr=et-1;
 42     et->c=0; et->in=i; et->nxt=eds[j]; eds[j]=et++; 
 43 }
 44 #define FOREACH_EDGE(i,j) for(edge*i=eds[j];i!=NULL;i=i->nxt)
 45 
 46 int n;
 47 
 48 int st,ed;
 49 int dep[200];
 50 ll DFS(int x,ll mi)
 51 {
 52     if(x==ed) return mi;
 53     ll res=0,c;
 54     FOREACH_EDGE(i,x)
 55     if(i->c>0 && dep[x]+1==dep[i->in] && (c=DFS(i->in,min(mi,i->c))) )
 56     {
 57         res+=c;
 58         i->c-=c;
 59         i->ptr->c+=c;
 60         mi-=c;
 61         if(mi<=0) break;
 62     }
 63     if(res<=0) dep[x]=-1;
 64     return res;
 65 }
 66 
 67 int qh,qt;
 68 int q[400];
 69 ll DINIC()
 70 {
 71     ll res=0;
 72     
 73     while(true)
 74     {
 75         memset(dep,0xFF,sizeof(int)*(n+1));
 76         
 77         qh=qt=0;
 78         q[qt++]=st;
 79         dep[st]=0;
 80         while(qh!=qt)
 81         {
 82             int&cur=q[qh];
 83             FOREACH_EDGE(i,cur)
 84             if(i->c>0 && dep[i->in]==-1)
 85             {
 86                 dep[i->in]=dep[cur]+1;
 87                 q[qt++]=i->in;
 88             }
 89             qh++;
 90         }
 91         
 92         if(dep[ed]==-1) break;
 93     
 94         res=max((ll)0,res);
 95         res+=DFS(st,LINF);
 96     }
 97     
 98     return res;
 99 }
100 
101 
102 //blocks define
103 #define ST(i) (i)
104 #define ED(i) ((i)+ntot)
105 
106 int ntot,m;
107 
108 int main()
109 {
110     int T;
111     scanf("%d",&T);
112     while(T--)
113     {
114         scanf("%d%d",&ntot,&m);
115         et=pool;
116         
117         ntot++;
118         n=ntot*2;
119         st=ED(0);
120         ed=ST(ntot-1);
121         
122         memset(eds,0,sizeof(int)*(n+1));
123         
124         for(int i=1;i<ntot-1;i++)
125         {
126             ll c;
127             scanf("%I64d",&c);
128             addedge(ST(i),ED(i),c);
129         }
130         
131         addedge(ST(0),ED(0),LINF);
132         addedge(ST(ntot-1),ED(ntot-1),LINF);
133         
134         for(int i=0;i<m;i++)
135         {
136             int a,b;
137             scanf("%d%d",&a,&b);
138             addedge(ED(b),ST(a),LINF);
139             addedge(ED(a),ST(b),LINF);
140         }
141 
142         ll res=DINIC();
143         
144         if(res==0) printf("Min!\n");
145         else if(res>=LINF) printf("Max!\n");
146         else printf("%I64d\n",res);
147     }
148     
149     return 0;
150 }
View Code

 



 

 


然后是类似于DINIC的最小费用流.多路增广.存图同上,这里省略了.

 1 int n;
 2 
 3 int st,ed;
 4 int dist[205];
 5 int cost_add;
 6 bool used[205];
 7 int DFS(int x,int mi)
 8 {
 9     if(x==ed)return mi;
10     
11     used[x]=true;
12     int res=0;
13     int c;
14     FOREACH_EDGE(i,x)
15     if(!used[i->in] && i->c>0 && dist[i->in]==dist[x]+i->v && (c=DFS(i->in,min(i->c,mi))))
16     {
17         i->c-=c;
18         i->ptr->c+=c;
19         mi-=c;
20         res+=c;
21         cost_add+=c*i->v;
22         if(mi<=0) break;
23     }
24     used[x]=false;
25     if(res<=0) dist[x]=INF;
26     return res;
27 }
28 
29 int q[1000000];
30 int qt,qh;
31 int DINIC()
32 {
33     int res=0;
34     
35     while(true)
36     {
37         for(int i=0;i<n;i++)
38         dist[i]=INF;
39         
40         qh=qt=0;
41         dist[st]=0;
42         q[qt++]=st;
43         while(qh!=qt)
44         {
45             int&cur=q[qh];
46             FOREACH_EDGE(i,cur)
47             {
48                 int&nxt=i->in;
49                 if(i->c>0 && i->v + dist[cur] < dist[nxt])
50                 {
51                     dist[nxt]=dist[cur]+i->v;
52                     q[qt++]=nxt;
53                 }
54             }
55             qh++;
56         }
57         
58         if(dist[ed]==INF) break;
59         
60         cost_add=0;
61         DFS(st,INF);
62         res+=cost_add;
63     }
64     
65     return res;
66 }
View Code

注意DFS中使用了used在深搜的时候避免搜到环(最短路图中可能存在0环).

 

 

AC BZOJ 1384

  1 #include <cstdio>
  2 #include <fstream>
  3 #include <iostream>
  4  
  5 #include <cstdlib>
  6 #include <cstring>
  7 #include <algorithm>
  8 #include <cmath>
  9  
 10 #include <queue>
 11 #include <vector>
 12 #include <map>
 13 #include <set>
 14 #include <stack>
 15 #include <list>
 16  
 17 typedef unsigned int uint;
 18 typedef long long int ll;
 19 typedef unsigned long long int ull;
 20 typedef double db;
 21  
 22 using namespace std;
 23  
 24 inline int getint()
 25 {
 26     int res=0;
 27     char c=getchar();
 28     bool mi=false;
 29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
 30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 31     return mi ? -res : res;
 32 }
 33 inline ll getll()
 34 {
 35     ll res=0;
 36     char c=getchar();
 37     bool mi=false;
 38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
 39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 40     return mi ? -res : res;
 41 }
 42 
 43 //==============================================================================
 44 //==============================================================================
 45 //==============================================================================
 46 //==============================================================================
 47 
 48 int INF=(1<<30)-1;
 49 
 50 struct edge
 51 {
 52     int in;
 53     int c;
 54     int v;
 55     edge*nxt;
 56     edge*ptr;
 57     bool rev;
 58 }pool[105000];
 59 int orgv[105000];
 60 edge*et=pool;
 61 edge*eds[1050];
 62 void addedge(int i,int j,int c,int v)
 63 {
 64     et->ptr=et+1; et->rev=false;
 65     et->in=j; et->c=c; et->v=v; et->nxt=eds[i]; eds[i]=et++;
 66     et->ptr=et-1; et->rev=true;
 67     et->in=i; et->c=0; et->v=-v; et->nxt=eds[j]; eds[j]=et++;
 68 }
 69 #define FOREACH_EDGE(i,j) for(edge*i=eds[j];i;i=i->nxt)
 70 
 71 int n;
 72 
 73 int cost;
 74 
 75 int dist[1050];
 76 int st,ed;
 77 bool used[1050];
 78 int DFS(int x,int mi)
 79 {
 80     if(x==ed) return mi;
 81     used[x]=true;
 82     int res=0,c;
 83     FOREACH_EDGE(i,x)
 84     if(i->c>0 && !used[i->in] && dist[x]+i->v==dist[i->in] && ( c=DFS(i->in,min(i->c,mi)) ))
 85     {
 86         i->c-=c;
 87         i->ptr->c+=c;
 88         res+=c;
 89         mi-=c;
 90         cost+=i->v*c;
 91         if(!mi) break;
 92     }
 93     if(!res) dist[x]=INF;
 94     used[x]=false;
 95     return res;
 96 }
 97 
 98 int q[4000000];
 99 int qh,qt;
100 int DINIC()
101 {
102     int res=0;
103     
104     while(true)
105     {
106         for(int i=0;i<=n;i++)
107         dist[i]=INF;
108         
109         qh=qt=0;
110         q[qt++]=st;
111         dist[st]=0;
112         while(qh!=qt)
113         {
114             int x=q[qh];
115             FOREACH_EDGE(i,x)
116             if(i->c>0 && dist[i->in]-dist[x]>i->v)
117             {
118                 dist[i->in]=dist[x]+i->v;
119                 q[qt++]=i->in;
120             }
121             qh++;
122         }
123         
124         if(dist[ed]==INF) break;
125         
126         res+=DFS(st,INF);
127     }
128     
129     return res;
130 }
131 
132 int m,k;
133 
134 edge*ote;
135 
136 int cap[105000];
137 int A[105000];
138 int B[105000];
139 int var[105000];
140 int etot=0;
141 
142 int main()
143 {
144     n=getint()+1;
145     m=getint();
146     k=getint();
147     st=1;
148     ed=n-1;
149     for(int i=0;i<m;i++)
150     {
151         int c;
152         A[i]=getint();
153         B[i]=getint();
154         c=getint();
155         orgv[i]=getint();
156         addedge(A[i],B[i],c,1);
157     }
158     
159     printf("%d ",DINIC());
160     
161     for(int i=1;i<n;i++)
162     FOREACH_EDGE(e,i) e->v=0;
163     
164     cost=0;
165     
166     for(int i=0;i<m;i++)
167     addedge(A[i],B[i],INF,orgv[i]);
168     
169     st=0;
170     addedge(st,1,k,0);
171     DINIC();
172     printf("%d\n",cost);
173     
174     
175     return 0;
176 }
View Code

把这个程序放上来,主要表示在原残量网络上建图,以及最大流与最小费的相互转化的基本方法.


AC BZOJ 1266

最短路图转最小割

  1 #include <cstdio>
  2 #include <fstream>
  3 #include <iostream>
  4  
  5 #include <cstdlib>
  6 #include <cstring>
  7 #include <algorithm>
  8 #include <cmath>
  9  
 10 #include <queue>
 11 #include <vector>
 12 #include <map>
 13 #include <set>
 14 #include <stack>
 15 #include <list>
 16  
 17 typedef unsigned int uint;
 18 typedef long long int ll;
 19 typedef unsigned long long int ull;
 20 typedef double db;
 21  
 22 using namespace std;
 23  
 24 inline int getint()
 25 {
 26     int res=0;
 27     char c=getchar();
 28     bool mi=false;
 29     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
 30     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 31     return mi ? -res : res;
 32 }
 33 inline ll getll()
 34 {
 35     ll res=0;
 36     char c=getchar();
 37     bool mi=false;
 38     while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
 39     while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
 40     return mi ? -res : res;
 41 }
 42 
 43 //==============================================================================
 44 //==============================================================================
 45 //==============================================================================
 46 //==============================================================================
 47 
 48 const int INF=(1<<30)-1;
 49 
 50 int n;
 51 
 52 struct ShortestPathGraph
 53 {
 54     struct edge
 55     {
 56         int in;
 57         int v;
 58         edge*nxt;
 59     }pool[205000];
 60     edge*et;
 61     edge*eds[1050];
 62     
 63     ShortestPathGraph(){ et=pool; }
 64     
 65     void addedge(int i,int j,int v)
 66     { et->in=j; et->v=v; et->nxt=eds[i]; eds[i]=et++; }
 67     
 68     void SPFA(int*dist,int st)
 69     {
 70         for(int i=0;i<n;i++) dist[i]=INF;
 71         typedef pair<int,int> pl;
 72         priority_queue<pl,vector<pl>,greater_equal<pl> > q;
 73         dist[st]=0; q.push(pl(dist[st],st));
 74         while(!q.empty())
 75         {
 76             int x=q.top().second;
 77             int d=q.top().first;
 78             q.pop();
 79             if(dist[x]<d) continue;
 80             for(edge*i=eds[x];i;i=i->nxt)
 81             if(dist[i->in]>dist[x]+i->v)
 82             {
 83                 dist[i->in]=dist[x]+i->v;
 84                 q.push(pl(dist[i->in],i->in));
 85             }
 86         }
 87     }
 88 };
 89 
 90 
 91 struct MaxflowGraph
 92 {
 93     struct edge
 94     {
 95         int in;
 96         int c;
 97         edge*nxt;
 98         edge*ptr;
 99     }pool[405000];
100     edge*et;
101     edge*eds[1050];
102     edge*cur[1050];
103     
104     int dep[1050];
105     
106     int st,ed;
107     MaxflowGraph(){ et=pool; }
108     MaxflowGraph(int s,int t):st(s),ed(t){ et=pool; }
109     
110     void addedge(int i,int j,int c)
111     {
112         et->ptr=et+1;
113         et->in=j; et->c=c; et->nxt=eds[i]; eds[i]=et++;
114         et->ptr=et-1;
115         et->in=i; et->c=0; et->nxt=eds[j]; eds[j]=et++;
116     }
117     
118     int DFS(int x,int mi)
119     {
120         if(x==ed) return mi;
121         int res=0,c;
122         for(edge*&i=cur[x];i;i=i->nxt)
123         if( i->c>0 && dep[i->in]==dep[x]+1 && ( c=DFS(i->in,min(i->c,mi)) ) )
124         {
125             i->c-=c;
126             i->ptr->c+=c;
127             res+=c;
128             mi-=c;
129             if(!mi) break;
130         }
131         if(!res) dep[x]=-1;
132         return res;
133     }
134     
135     int DINIC()
136     {
137         int res=0;
138         
139         while(true)
140         {
141             memset(dep,0xFF,sizeof(int)*(n+1));
142             queue<int> q;
143             q.push(st); dep[st]=0;
144             while(!q.empty())
145             {
146                 int x=q.front(); q.pop();
147                 for(edge*i=eds[x];i;i=i->nxt)
148                 if(i->c>0 && dep[i->in]==-1)
149                 {
150                     dep[i->in]=dep[x]+1;
151                     if(i->in==ed) break;
152                     q.push(i->in);
153                 }
154             }
155             if(dep[ed]==-1) break;
156             memcpy(cur,eds,sizeof(edge*)*(n+1));
157             res+=DFS(st,INF);
158         }
159         
160         return res;
161     }
162     
163 };
164 
165 
166 int m;
167 
168 int A[205000];
169 int B[205000];
170 int D[205000];
171 int C[205000];
172 
173 ShortestPathGraph G;
174 MaxflowGraph F;
175 
176 int dist[10050];
177 
178 
179 int main()
180 {
181     n=getint();
182     m=getint();
183     for(int i=0;i<m;i++)
184     {
185         A[i]=getint()-1;
186         B[i]=getint()-1;
187         D[i]=getint();
188         C[i]=getint();
189         G.addedge(A[i],B[i],D[i]);
190         G.addedge(B[i],A[i],D[i]);
191     }
192     
193     G.SPFA(dist,0);
194     printf("%d\n",dist[n-1]);
195     
196     for(int i=0;i<m;i++)
197     {
198         if(dist[A[i]]+D[i]==dist[B[i]])
199         F.addedge(A[i],B[i],C[i]);
200         if(dist[B[i]]+D[i]==dist[A[i]])
201         F.addedge(B[i],A[i],C[i]);
202     }
203     
204     F.st=0;
205     F.ed=n-1;
206     printf("%d\n",F.DINIC());
207     
208     
209     return 0;
210 }
View Code

昨天WA了7次,今天重写一遍就A了.....

还是不知道原来错在哪....可能是双向边的处理.....

注意原图无向,但最短路图是有向的,对于原图每条边(x,y),重构图时(x,y)与(y,x)都要判断,并且分开连边.

写多图(图转图)的题千万不要总想着去节约代码量! 清晰的结构带来的效率远比节约四分之一代码量要高......

 

posted @ 2014-12-06 10:19  DragoonKiller  阅读(189)  评论(0编辑  收藏  举报