算法模板之图论

一、二分图

1、最大匹配数 = 最大流 = 最小割 = 最小点集覆盖 = 总点数 - 最大独立集

2、KM算法(最佳完美匹配

 1 int mat[MAXN][MAXN], slack[MAXN], Lx[MAXN], Ly[MAXN], left[MAXN];   
 2 bool S[MAXN], T[MAXN];   
 3        
 4 bool dfs(int i)   
 5 {   
 6     S[i] = true;   
 7     for(int j = 1; j <= n; ++j) if(!T[j]) {   
 8         int t = Lx[i] + Ly[j] - mat[i][j];   
 9         if(t == 0){   
10             T[j] = true;   
11             if(!left[j] || dfs(left[j])){   
12                 left[j] = i;   
13                 return true;   
14             }   
15         }   
16         else slack[j] = min(slack[j],t);   
17     }   
18     return false;   
19 }   
20        
21 void update()   
22 {   
23     int a = INF;   
24     for(int i = 1; i <= n; ++i) if(!T[i])   
25         a = min(slack[i],a);   
26     for(int i = 1; i <= n; ++i){   
27         if(S[i]) Lx[i] -= a;   
28         if(T[i]) Ly[i] += a; else slack[i] -= a;   
29     }   
30 }   
31        
32 int KM()   
33 {   
34     for(int i = 1; i <= n; ++i){   
35         Lx[i] = Ly[i] = left[i] = 0;   
36         for(int j = 1; j <= n; ++j) Lx[i] = max(Lx[i],mat[i][j]);   
37     }   
38     for(int i = 1; i <= n; ++i){   
39         for(int j = 1; j <= n; ++j) slack[j] = INF;   
40         while(1){   
41             for(int j = 1; j <= n; ++j) S[j] = T[j] = 0;   
42             if(dfs(i)) break; else update();   
43         }   
44     }   
45     int ans = 0;   
46     for(int i = 1; i <=n; ++i) ans += Lx[i] +Ly[i];   
47     return ans;   
48 }
View Code

3、匈牙利(最大匹配)(Update:2014年11月8日)

 1 bool dfs(int u) {
 2     for(int v : edge[u]) if(!vis[v]) {//c++11
 3         vis[v] = true;
 4         if(!link[v] || dfs(link[v])) {
 5             link[v] = u;
 6             return true;
 7         }
 8     }
 9     return false;
10 }
11 
12 int hungary() {
13     int res = 0;
14     for(int i = 1; i <= n; ++i) {
15         memset(vis + 1, 0, m * sizeof(bool));
16         res += dfs(i);
17     }
18     return res;
19 }
View Code

4、2-SAT(若sccno[2i]<sccno[2i+1]就选i,否则选i的对立面

 1 struct TwoSAT{
 2     int St[MAXN], c;
 3     int n, ecnt, dfs_clock, scc_cnt;
 4     int head[MAXN], sccno[MAXN], pre[MAXN], lowlink[MAXN];
 5     int next[MAXM], to[MAXM];
 6 
 7     void dfs(int u){
 8         lowlink[u] = pre[u] = ++dfs_clock;
 9         St[++c] = u;
10         for(int p = head[u]; p; p = next[p]){
11             int &v = to[p];
12             if(!pre[v]){
13                 dfs(v);
14                 if(lowlink[u] > lowlink[v]) lowlink[u] = lowlink[v];
15             }else if(!sccno[v]){
16                 if(lowlink[u] > pre[v]) lowlink[u] = pre[v];
17             }
18         }
19         if(lowlink[u] == pre[u]){
20             ++scc_cnt;
21             while(true){
22                 int x = St[c--];
23                 sccno[x] = scc_cnt;
24                 if(x == u) break;
25             }
26         }
27     }
28 
29     void init(int nn){
30         n = nn;
31         ecnt = 2; dfs_clock = scc_cnt = 0;
32         memset(head,0,sizeof(head));
33         memset(pre,0,sizeof(pre));
34         memset(sccno,0,sizeof(sccno));
35     }
36 
37     void addEdge(int x, int y){//x, y clash
38         to[ecnt] = y^1; next[ecnt] = head[x]; head[x] = ecnt++;
39         to[ecnt] = x^1; next[ecnt] = head[y]; head[y] = ecnt++;
40         //printf("%d<>%d\n",x,y);
41     }
42 
43     bool solve(){
44         for(int i = 0; i < n; ++i)
45             if(!pre[i]) dfs(i);
46         for(int i = 0; i < n; i += 2)
47             if(sccno[i] == sccno[i^1]) return false;
48         return true;
49     }
50 } G;
View Code

二、网络流

1、DINIC,带容量上届(Update:2014年11月8日)

 1 struct DINIC {
 2     int head[MAXV], ecnt;
 3     int to[MAXE], next[MAXE], cap[MAXE], flow[MAXE];
 4     int n, st, ed;
 5 
 6     void init(int n) {
 7         this->n = n;
 8         memset(head + 1, -1, n * sizeof(int));
 9         ecnt = 0;
10     }
11 
12     void add_edge(int u, int v, int c) {
13         to[ecnt] = v; cap[ecnt] = c; flow[ecnt] = 0; next[ecnt] = head[u]; head[u] = ecnt++;
14         to[ecnt] = u; cap[ecnt] = 0; flow[ecnt] = 0; next[ecnt] = head[v]; head[v] = ecnt++;
15     }
16 
17     bool vis[MAXV];
18     int dis[MAXV], cur[MAXV];
19 
20     bool bfs() {
21         memset(vis + 1, 0, n * sizeof(bool));
22         queue<int> que; que.push(st);
23         dis[st] = 0; vis[st] = true;
24         while(!que.empty()) {
25             int u = que.front(); que.pop();
26             for(int p = head[u]; ~p; p = next[p]) {
27                 int v = to[p];
28                 if(!vis[v] && cap[p] > flow[p]) {
29                     vis[v] = true;
30                     dis[v] = dis[u] + 1;
31                     que.push(v);
32                 }
33             }
34         }
35         return vis[ed];
36     }
37 
38     int dfs(int u, int a) {
39         if(u == ed || a == 0) return a;
40         int outflow = 0, f;
41         for(int &p = cur[u]; ~p; p = next[p]) {
42             int v = to[p];
43             if(dis[u] + 1 == dis[v] && (f = dfs(v, min(a, cap[p] - flow[p]))) > 0) {
44                 flow[p] += f;
45                 flow[p ^ 1] -= f;
46                 outflow += f;
47                 a -= f;
48                 if(a == 0) break;
49             }
50         }
51         return outflow;
52     }
53 
54     int maxflow(int ss, int tt) {
55         st = ss, ed = tt;
56         int res = 0;
57         while(bfs()) {
58             memcpy(cur + 1, head + 1, n * sizeof(int));
59             res += dfs(st, INF);
60         }
61         return res;
62     }
63 } G;
View Code

2、ISAP,带BFS优化

 1 struct SAP {
 2     int head[MAXV];
 3     int gap[MAXV], dis[MAXV], pre[MAXV], cur[MAXV];
 4     int to[MAXE], flow[MAXE], next[MAXE];
 5     int ecnt, st, ed, n;
 6 
 7     void init(int ss, int tt, int nn) {
 8         memset(head, -1, sizeof(head));
 9         ecnt = 0;
10         st = ss; ed = tt; n = nn;
11     }
12 
13     void addEdge(int u,int v,int f) {
14         to[ecnt] = v; flow[ecnt] = f; next[ecnt] = head[u]; head[u] = ecnt++;
15         to[ecnt] = u; flow[ecnt] = 0; next[ecnt] = head[v]; head[v] = ecnt++;
16     }
17 
18     void bfs() {
19         memset(dis, 0x3f, sizeof(dis));
20         queue<int> que; que.push(ed);
21         dis[ed] = 0;
22         while(!que.empty()) {
23             int u = que.front(); que.pop();
24             ++gap[dis[u]];
25             for(int p = head[u]; ~p; p = next[p]) {
26                 int v = to[p];
27                 if (dis[v] > ed && flow[p ^ 1] > 0) {
28                     dis[v] = dis[u] + 1;
29                     que.push(v);
30                 }
31             }
32         }
33     }
34 
35     int Max_flow() {
36         int ans = 0, minFlow = INF, u;
37         for (int i = 0; i <= n; ++i){
38             cur[i] = head[i];
39             gap[i] = dis[i] = 0;
40         }
41         u = pre[st] = st;
42         //gap[0] = n;
43         bfs();
44         while (dis[st] < n){
45             bool flag = false;
46             for (int &p = cur[u]; ~p; p = next[p]){
47                 int v = to[p];
48                 if (flow[p] > 0 && dis[u] == dis[v] + 1){
49                     flag = true;
50                     minFlow = min(minFlow, flow[p]);
51                     pre[v] = u;
52                     u = v;
53                     if(u == ed){
54                         ans += minFlow;
55                         while (u != st){
56                             u = pre[u];
57                             flow[cur[u]] -= minFlow;
58                             flow[cur[u] ^ 1] += minFlow;
59                         }
60                         minFlow = INF;
61                     }
62                     break;
63                 }
64             }
65             if (flag) continue;
66             int minDis = n-1;
67             for (int p = head[u]; ~p; p = next[p]){
68                 int v = to[p];
69                 if (flow[p] && dis[v] < minDis){
70                     minDis = dis[v];
71                     cur[u] = p;
72                 }
73             }
74             if (--gap[dis[u]] == 0) break;
75             gap[dis[u] = minDis+1]++;
76             u = pre[u];
77         }
78         return ans;
79     }
80 } G;
View Code

3、Stoer-Wagner(全图最小割)

 

 1 LL mat[MAXN][MAXN];
 2 LL weight[MAXN];
 3 bool del[MAXN], vis[MAXN];;
 4 int n, m, st;
 5 
 6 void init() {
 7     memset(mat, 0, sizeof(mat));
 8     memset(del, 0, sizeof(del));
 9 }
10 
11 LL StoerWagner(int &s, int &t, int cnt) {
12     memset(weight, 0, sizeof(weight));
13     memset(vis, 0, sizeof(vis));
14     for(int i = 1; i <= n; ++i)
15         if(!del[i]) {t = i; break; }
16     while(--cnt) {
17         vis[s = t] = true;
18         for(int i = 1; i <= n; ++i) if(!del[i] && !vis[i]) {
19             weight[i] += mat[s][i];
20         }
21         t = 0;
22         for(int i = 1; i <= n; ++i) if(!del[i] && !vis[i]) {
23             if(weight[i] >= weight[t]) t = i;
24         }
25     }
26     return weight[t];
27 }
28 
29 void merge(int s, int t) {
30     for(int i = 1; i <= n; ++i) {
31         mat[s][i] += mat[t][i];
32         mat[i][s] += mat[i][t];
33     }
34     del[t] = true;
35 }
36 
37 LL solve() {
38     LL ret = -1;
39     int s, t;
40     for(int i = n; i > 1; --i) {
41         if(ret == -1) ret = StoerWagner(s, t, i);
42         else ret = min(ret, StoerWagner(s, t, i));
43         merge(s, t);
44     }
45     return ret;
46 }
47 
48 int main() {
49     while(scanf("%d%d%d", &n, &m, &st) != EOF) {
50         if(n == 0 && m == 0 && st == 0) break;
51         init();
52         while(m--) {
53             int x, y, z;
54             scanf("%d%d%d", &x, &y, &z);
55             mat[x][y] += z;
56             mat[y][x] += z;
57         }
58         cout<<solve()<<endl;
59     }
60 }
View Code

 

4、二分图的网络流

1 /*
2 最大权闭合图,S到正权点连边,负权点到T连边,对于每一个i→j,连一条无穷大的边。残量网络中与S关联的点为所选,正权和 - 最大流 = 答案
3 最小点权覆盖 = 最大流
4 最大权独立集 = 点权和 - 最大流
5 */
View Code

三、费用流

1、ZKW费用流(适用于二分图、稠密图)

 1 struct ZEK_FLOW {
 2     int head[MAXV], dis[MAXV];
 3     int next[MAXE], to[MAXE], cap[MAXE], cost[MAXE];
 4     int n, ecnt, st, ed;
 5 
 6     void init() {
 7         memset(head, -1, sizeof(head));
 8         ecnt = 0;
 9     }
10 
11     void add_edge(int u, int v, int c, int w) {
12         to[ecnt] = v; cap[ecnt] = c; cost[ecnt] = w; next[ecnt] = head[u]; head[u] = ecnt++;
13         to[ecnt] = u; cap[ecnt] = 0; cost[ecnt] = -w; next[ecnt] = head[v]; head[v] = ecnt++;
14     }
15 
16     void SPFA() {
17         for(int i = 1; i <= n; ++i) dis[i] = INF;
18         priority_queue<pair<int, int> > que;
19         dis[st] = 0; que.push(make_pair(0, st));
20         while(!que.empty()) {
21             int u = que.top().second, d = -que.top().first; que.pop();
22             if(d != dis[u]) continue;
23             for(int p = head[u]; ~p; p = next[p]) {
24                 int &v = to[p];
25                 if(cap[p] && dis[v] > d + cost[p]) {
26                     dis[v] = d + cost[p];
27                     que.push(make_pair(-dis[v], v));
28                 }
29             }
30         }
31         int t = dis[ed];
32         for(int i = 1; i <= n; ++i) dis[i] = t - dis[i];
33     }
34 
35     int minCost, maxFlow;
36     bool vis[MAXV];
37 
38     int add_flow(int u, int aug) {
39         if(u == ed) {
40             maxFlow += aug;
41             minCost += dis[st] * aug;
42             return aug;
43         }
44         vis[u] = true;
45         int now = aug;
46         for(int p = head[u]; ~p; p = next[p]) {
47             int &v = to[p];
48             if(cap[p] && !vis[v] && dis[u] == dis[v] + cost[p]) {
49                 int t = add_flow(v, min(now, cap[p]));
50                 cap[p] -= t;
51                 cap[p ^ 1] += t;
52                 now -= t;
53                 if(!now) break;
54             }
55         }
56         return aug - now;
57     }
58 
59     bool modify_label() {
60         int d = INF;
61         for(int u = 1; u <= n; ++u) if(vis[u]) {
62             for(int p = head[u]; ~p; p = next[p]) {
63                 int &v = to[p];
64                 if(cap[p] && !vis[v]) d = min(d, dis[v] + cost[p] - dis[u]);
65             }
66         }
67         if(d == INF) return false;
68         for(int i = 1; i <= n; ++i) if(vis[i]) dis[i] += d;
69         return true;
70     }
71 
72     int min_cost_flow(int ss, int tt, int nn) {
73         st = ss, ed = tt, n = nn;
74         minCost = maxFlow = 0;
75         SPFA();
76         while(true) {
77             while(true) {
78                 for(int i = 1; i <= n; ++i) vis[i] = 0;
79                 if(!add_flow(st, INF)) break;
80             }
81             if(!modify_label()) break;
82         }
83         return minCost;
84     }
85 } G;
View Code

2、SPFA费用流(Update:2014年8月7日)

 1 struct SPFA_COST_FLOW {
 2     int head[MAXV];
 3     int to[MAXE], next[MAXE], cap[MAXE], flow[MAXE];
 4     LL cost[MAXE];
 5     int n, m, ecnt, st, ed;
 6 
 7     void init(int n) {
 8         this->n = n;
 9         memset(head + 1, -1, n * sizeof(int));
10         ecnt = 0;
11     }
12 
13     void add_edge(int u, int v, int f, LL c) {
14         to[ecnt] = v; cap[ecnt] = f; cost[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++;
15         to[ecnt] = u; cap[ecnt] = 0; cost[ecnt] = -c; next[ecnt] = head[v]; head[v] = ecnt++;
16     }
17 
18     void clear() {
19         memset(flow, 0, ecnt * sizeof(int));
20     }
21 
22     LL dis[MAXV];
23     int pre[MAXV];
24     bool vis[MAXV];
25 
26     bool spfa() {
27         memset(vis + 1, 0, n * sizeof(bool));
28         memset(dis, 0x3f, (n + 1) * sizeof(LL));
29         queue<int> que; que.push(st);
30         dis[st] = 0;
31         while(!que.empty()) {
32             int u = que.front(); que.pop();
33             vis[u] = false;
34             for(int p = head[u]; ~p; p = next[p]) {
35                 int v = to[p];
36                 if(cap[p] - flow[p] && dis[u] + cost[p] < dis[v]) {
37                     dis[v] = dis[u] + cost[p];
38                     pre[v] = p;
39                     if(!vis[v]) {
40                         que.push(v);
41                         vis[v] = true;
42                     }
43                 }
44             }
45         }
46         return dis[ed] < dis[0];
47     }
48 
49     LL maxFlow, minCost;
50 
51     LL min_cost_flow(int ss, int tt) {
52         st = ss, ed = tt;
53         maxFlow = minCost = 0;
54         while(spfa()) {
55             int u = ed, tmp = INF;
56             while(u != st) {
57                 tmp = min(tmp, cap[pre[u]] - flow[pre[u]]);
58                 u = to[pre[u] ^ 1];
59             }
60             u = ed;
61             while(u != st) {
62                 flow[pre[u]] += tmp;
63                 flow[pre[u] ^ 1] -= tmp;
64                 u = to[pre[u] ^ 1];
65             }
66             maxFlow += tmp;
67             minCost += tmp * dis[ed];
68         }
69         return minCost;
70     }
71 } G;
View Code

四、连通分量

1、强连通分量

 1 void dfs(int u) {//tarjan
 2     pre[u] = lowlink[u] = ++dfs_clock;
 3     stk[++top] = u;
 4     for(int p = head[u]; ~p; p = next[p]) {
 5         int &v = to[p];
 6         if(!pre[v]) {
 7             dfs(v);
 8             if(lowlink[u] > lowlink[v]) lowlink[u] = lowlink[v];
 9         } else if(!sccno[v]) {
10             if(lowlink[u] > pre[v]) lowlink[u] = pre[v];
11         }
12     }
13     if(lowlink[u] == pre[u]) {
14         ++scc_cnt;
15         while(true) {
16             int x = stk[top--];
17             sccno[x] = scc_cnt;
18             if(x == u) break;
19         }
20     }
21 }
View Code

2、双连通分量

 1 void dfs(int u) {
 2     pre[u] = lowlink[u] = ++dfs_clock;
 3     stk[top++] = u;
 4     for(int p = head[u]; ~p; p = next[p]) {
 5         if(vis[p]) continue;
 6         vis[p] = vis[p ^ 1] = true;
 7         int &v = to[p];
 8         if(!pre[v]) {
 9             dfs(v);
10             lowlink[u] = min(lowlink[u], lowlink[v]);
11         } else lowlink[u] = min(lowlink[u], pre[v]);
12     }
13     if(lowlink[u] == pre[u]) {
14         ++scc_cnt;
15         while(true) {
16             int x = stk[--top];
17             sccno[x] = scc_cnt;
18             if(x == u) break;
19         }
20     }
21 }
View Code

3、双连通分量-缩边

 1 void tarjan(int u, int f) {
 2     pre[u] = lowlink[u] = ++dfs_clock;
 3     int child = 0;
 4     for(int p = head[u]; ~p; p = next[p]) {
 5         if(vis[p]) continue;
 6         vis[p] = vis[p ^ 1] = true;
 7         stk[++top] = p;
 8         int &v = to[p];
 9         if(!pre[v]) {
10             ++child;
11             tarjan(v, u);
12             lowlink[u] = min(lowlink[u], lowlink[v]);\
13             if(pre[u] <= lowlink[v]) {
14                 iscut[u] = true;
15                 ++scc_cnt;
16                 while(true) {
17                     int t = stk[top--];
18                     scc_edge[t] = scc_edge[t ^ 1] = scc_cnt;
19                     if(t == p) break;
20                 }
21             }
22         } else lowlink[u] = min(lowlink[u], pre[v]);
23     }
24     if(f < 1 && child == 1) iscut[u] = false;
25 }
View Code

五、树

1、tarjan求LCA

 1 void lca(int u, int f, int deep) {
 2     dep[u] = deep;
 3     for(int p = head[u]; ~p; p = next[p]) {
 4         int &v = to[p];
 5         if(v == f || vis[v]) continue;
 6         lca(v, u, deep + 1);
 7         fa[v] = u;
 8     }
 9     vis[u] = true;
10     for(vector<PII>::iterator it = query[u].begin(); it != query[u].end(); ++it) {
11         if(vis[it->first]) {
12             ans[it->second] = (dep[u] + dep[it->first] - 2 * dep[find_set(it->first)]) / 2;
13         }
14     }
15 }
View Code

 

posted @ 2013-08-19 23:11  Oyking  阅读(372)  评论(0编辑  收藏  举报