@@ -190,3 +190,236 @@ void dfs(int u,int fa){
190
190
if(fa == -1 && cl == 1)cut[ u] = 0;//根节点
191
191
}
192
192
```
193
+ # 强联通分量分解
194
+ ```c++
195
+
196
+
197
+
198
+ std::vector<int> G[MAX_V];
199
+ std::vector<int> rG[MAX_V];
200
+ bool vis[MAX_V];
201
+ int scc[MAX_V];
202
+ std::vector<int> vs;//访问结束时间栈
203
+ void add_edge(int u,int v){
204
+ G[u].push_back(v);
205
+ G[v].push_back(u);
206
+ }
207
+ void dfs(int u) {
208
+ vis[u] = true;
209
+ for(int i=0 ; i<G[u].size() ;++i)
210
+ if(!vis[G[u][i]])dfs(G[u][i]);
211
+ vs.push_back(u);
212
+ }
213
+
214
+ void rdfs(int u,int scc_cnt) {
215
+ vis[u] = true;
216
+ scc[u] = scc_cnt;
217
+ for(int i=0 ; i<rG[u].size() ; ++i)
218
+ if(!vis[rG[u][i]])rdfs(rG[u][i]);
219
+ }
220
+
221
+ int Kosaraju(int nv){
222
+ int scc_cnt = 0;
223
+ memset(vis,false,sizeof(vis));
224
+ vs.clear();
225
+ for(int i=0 ; i<v ; ++i)
226
+ if(!vis[i])dfs(i);
227
+ memset(vis,false,sizeof(vis));
228
+ for(int i= vs.size()-1 ; i>=0 ; --i)
229
+ if(!vis[vs[i]])rdfs(vs[i],++scc_cnt);
230
+ return scc_cnt;
231
+ }
232
+
233
+ ```
234
+ # 网络流
235
+ ##Dinic
236
+ ``` c++
237
+
238
+ struct Edge {
239
+ int from,to,cap;
240
+ Edge (int u,int v,int c = 0): from (u),to(v),cap(c){};
241
+ };
242
+
243
+ //残量网络
244
+ void add_edge(int u,int v,int cap){
245
+ E.push_back(Egde(u,v,cap));G[ u] .push_back(E.size()-1);
246
+ E.push_back(Edge(v,u,0)); G[ v] .push_back(E.size()-1);
247
+ }
248
+
249
+ struct Dinic{
250
+ std::vector<Edge > E;
251
+ std::vector<int > G[ MAX_V] ;
252
+ int level[ MAX_V] ,cur[ MAX_V] ;//分层,当前弧;
253
+ void bfs(int s){
254
+ memset(level,-1,sizeof(level));
255
+ queue<int > Q;Q.push(s);
256
+ level[ s] = 0;
257
+ while (!Q.empty()) {
258
+ int u = Q.front();Q.pop();
259
+ for(int i=0 ; i<G[ u] .size() ; ++i){
260
+ Edge & e = E[ G[ u] [ i ]] ;
261
+ if(e.cap>0 && level[ e.to] <0){
262
+ level[ e.to] = level[ u] +1;
263
+ Q.push(e.to);
264
+ }
265
+ }
266
+ }
267
+ }
268
+
269
+ int dfs(int v,int t,int f){
270
+ if(v==t || f == 0)return f;
271
+ for(int& i = cur[ v] ; i<G[ v] .size() ; ++i){
272
+ Edge & e = E[ G[ v] [ i ]] ;Edge & rev = E[ G[ v] [ i ] ^1] ;
273
+ if(e.cap>0 && level[ v] <level[ e.to] ){
274
+ int a = dfs(e.to,t,min(f,e.cap));
275
+ if(a>0){
276
+ e.cap-=a;
277
+ rev.cap+=a;
278
+ return a;
279
+ }
280
+ }
281
+ }
282
+ return 0;
283
+ }
284
+
285
+ int max_flow(int s,int t){
286
+ int flow = 0;
287
+ for(;;){
288
+ bfs(s);
289
+ if(level[ t] <0)break;
290
+ memset(cur,0,sizeof(cur));
291
+ int f;
292
+ while ((f = dfs(s,t,INF))>0) {
293
+ flow+=f;
294
+ }
295
+ }
296
+ return flow;
297
+ }
298
+ }
299
+
300
+ ```
301
+ 对于上面的建边的方式,e的反向边就是e^1,这个可以自行枚举证明.
302
+
303
+ ##最大流最小切割定理
304
+ 以下三个条件等价:
305
+ 1. $f$ 是 $G$ 的最大流.
306
+ 2. 残存网络中没有增广路
307
+ 3. $|f| = c(S,T)$ 其中(S,T)是最小切割
308
+
309
+ ###切割
310
+
311
+ $G$的某个切割 $\{S,T\}$ 是指,将图分为两个不相交的集合,$\{S,T\}$ 的容量为,从 ${S}$ d到 $T$ 的最大容量,即割边的最大容量
312
+
313
+ #二分图匹配
314
+ 二分图的一个匹配是指二分图中的一些没有公共顶点的边集,匹配数就是边集的数目,最大匹配是指,使得这样的边集的数目最大.
315
+
316
+ ##算法
317
+ 当作网络流来处理,将$U 与 V$ 的边改成从 $U 流入 V$ 的一条边,其容量为一.对于这个多元多汇问题,我们只需要连一个超级节点 $S$ 到每一个源点,容量为1,再从每一个汇点连到一个超级汇点 容量也为一,这样这个图的最大流就是最大匹配数.
318
+
319
+ 不过由于是二分图我们可不必真的这样实现
320
+
321
+ **Code**
322
+ ```c++
323
+ int V;
324
+ std::vector<int> G[MAX_V];
325
+ bool used[MAX_V];
326
+ int match[MAX_V];
327
+
328
+ bool dfs(int u){
329
+ used[u] = true;
330
+ for(int i=0 ; i<G[u].size() ; ++i){
331
+ int v = G[u][i];int w = match[v];
332
+ if(w<0 || !used[w] && dfs(w)){
333
+ match[u] = v;match[v] = u;
334
+ return true;
335
+ }
336
+ }
337
+ return false;
338
+ }
339
+
340
+ int bipartite_match(){
341
+ int res = 0;
342
+ memset(match,-1,sizeof(match));
343
+ for(int i = 1 ; i<=V ; ++i){
344
+ if(match[i]<0){
345
+ memset(used,false,sizeof(used));
346
+ if(dfs(i))res++;
347
+ }
348
+ }
349
+ return res;
350
+ }
351
+
352
+ void add_edge(int u,int v){
353
+ G[u].push_back(v);
354
+ G[v].push_back(u);
355
+ }
356
+ ```
357
+
358
+ #最小费用流
359
+ 在概念上最小费用流只是在最大流的边上在附加一个费用,即求出从源点到汇点的给定流量的最小费用.
360
+
361
+ ##算法
362
+ 先从源点找一条到汇点的最短路,然后沿着最短路增广.建图的时候将反向边的费用设为-cost.(退流退费用)
363
+
364
+ ** Code**
365
+
366
+ ``` c++
367
+ struct Edge {
368
+ int from,to,cap,cost;
369
+ Edge (int f,int t,int c,int co): from (f),to(t),cap(c),cost(co){}
370
+ };
371
+ std::vector<Edge > E;
372
+ std::vector<int > G[ MAX_V] ;
373
+ void add_edge(int u,int v,int cap,int cost){
374
+ E.push_back(Edge(u,v,cap,cost));G[ u] .push_back(E.size()-1);
375
+ E.push_back(Edge(v,u,0,-cost)) ;G[ v] .push_back(E.size()-1);
376
+ }
377
+ struct MCMF{
378
+ int V;
379
+ int dist[ MAX_V] ;
380
+ int pre_E[ MAX_V] ;//最短路径弧
381
+ bool inq[ MAX_V] ;//spfa判断
382
+ //未判断负圈
383
+ void spfa(int s){
384
+ memset(dist,INF,sizeof(dist));
385
+ memset(inq,false,sizeof(inq));
386
+ queue<int > Q;
387
+ Q.push(s);
388
+ dist[ s] = 0;
389
+ inq[ s] = true;
390
+ pre_E[ s] = -1;
391
+ while(!Q.empty())
392
+ {
393
+ int u = Q.front();Q.pop();
394
+ inq[ u] = false;
395
+ for(int i=0 ; i<G[ u] .size() ; ++i){
396
+ Edge &e = E[ G[ u] [ i ]] ;
397
+ if(e.cap>0&&dist[ e.to] >dist[ u] +e.cost){
398
+ dist[ e.to] = dist[ u] +e.cost;
399
+ pre_E[ e.to] = G[ u] [ i ] ;
400
+ if(!inq[ e.to] ){Q.push(e.to);inq[ e.to] = true;}
401
+ }
402
+ }
403
+ }
404
+ }
405
+
406
+ int min_cost_flow(int s,int t,int f){
407
+ int res = 0;
408
+ while (f>0) {
409
+ spfa(s);
410
+ if(dist[ t] ==INF)return break;//不能增广
411
+ //沿着最短路增广
412
+ int d = f;
413
+ for(int i = pre_E[ t] ; i!=-1 ;i = pre_E[ E[ i] .from] )d = min(d,E[ i] .cap);
414
+ f-=d;
415
+ res+=d* dist[ t] ;
416
+ for(int i = pre_E[ t] ; i!=-1 ;i = pre_E[ E[ i] .from] ){
417
+ E[ i] .cap-=d;
418
+ E[ i^1] .cap+=d;
419
+ }
420
+ }
421
+ return res;
422
+ }
423
+ };
424
+
425
+ ```
0 commit comments