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 }
耗时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 }
然后是类似于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 }
注意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 }
把这个程序放上来,主要表示在原残量网络上建图,以及最大流与最小费的相互转化的基本方法.
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 }
昨天WA了7次,今天重写一遍就A了.....
还是不知道原来错在哪....可能是双向边的处理.....
注意原图无向,但最短路图是有向的,对于原图每条边(x,y),重构图时(x,y)与(y,x)都要判断,并且分开连边.
写多图(图转图)的题千万不要总想着去节约代码量! 清晰的结构带来的效率远比节约四分之一代码量要高......