一、二分图
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 }
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 }
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;
二、网络流
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;
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;
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 }
4、二分图的网络流
1 /* 2 最大权闭合图,S到正权点连边,负权点到T连边,对于每一个i→j,连一条无穷大的边。残量网络中与S关联的点为所选,正权和 - 最大流 = 答案 3 最小点权覆盖 = 最大流 4 最大权独立集 = 点权和 - 最大流 5 */
三、费用流
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;
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;
四、连通分量
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 }
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 }
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 }
五、树
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 }