算法模板之图论

一、二分图

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

 

你可能感兴趣的:(算法)