模板-图论
圖論算法相關(guān)模版, 可能有錯(cuò)誤, 省選前持續(xù)更正中
重要的不是模版內(nèi)容, 而是提供算法的實(shí)現(xiàn)思路.
struct SPFA {int n, m, s, t;int d[maxn];bool ban[maxn], inq[maxn];vectoredges;vectorG[maxn];void init(int n, int s, int t) {this->n = n;this->s = s;this->t = t;}void AddEdge(int from, int to, int dist) {edges.push_back((Edge) {from, to, dist});edges.push_back((Edge) {to, from, dist});m = edges.size();G[from].push_back(m-2);G[to].push_back(m-1);}int spfa(int x, int y) {queueQ;memset(d, 0x3f, sizeof(d));Q.push(s);inq[s] = 1;d[s] = 0;while(!Q.empty()) {int u = Q.front();Q.pop();inq[u] = 0;for(int i = 0; i < G[u].size(); i++) {Edge& e = edges[G[u][i]];if(!ban[e.to] && d[e.to] > d[u] + e.dist) {d[e.to] = d[u] + e.dist;if(!inq[e.to]) Q.push(e.to), inq[e.to] = 1;}}}return d[t];} };struct Dijkstra {int n, m;vectoredges;vectorG[maxn]; bool done[maxn]; int d[maxn], p[maxn]; void init(int n) { this->n = n; for(int i = 0; i < n; i++) G[i].clear(); edges.clear(); } void AddEdge(int from, int to, int dist) { edges.push_back((Edge) {from, to, dist}); m = edges.size(); G[from].push_back(m-1); } void dijkstra(int s) { priority_queueQ; // HeapNode 自定義結(jié)構(gòu)體 // 存儲(chǔ)二元組 {結(jié)點(diǎn)距s距離(dist), 結(jié)點(diǎn)編號(hào)(u)} // 并根據(jù) dist 進(jìn)行排序 for(int i = 0; i < n; i++) d[i] = INF; d[s] = 0; memset(done, 0, sizeof(done)); // 永久編號(hào) Q.push((HeapNode){0, s}); while(!Q.empty()) { HeapNode x = Q.top(); Q.pop(); int u = x.u; if(done[u]) continue; done[u] = true; for(int i = 0; i < G[u].size(); i++) { Edge& e = edges[G[u][i]]; if(d[e.to] > d[u] + e.dist) { d[e.to] = d[u] + e.dist; p[e.to] = G[u][i]; Q.push((HeapNode){d[e.to], e.to}); } } } } void GetShortestPaths(int s, int* dist, vector* paths) { dijkstra(s); for(int i = 0; i < n; i++) { dist[i] = d[i]; paths[i].clear(); int t = i; paths[i].push_back(t); while(t != s) { paths[i].push_back(edges[p[t]].from); t = edges[p[t]].from; } reverse(paths[i].begin(), paths[i].end()); } } }; struct MST { int n, m; void AddEdge(int from, int to, int dist) { edges.push_back((Edge){from, to, dist}); m = edges.size(); G[from].push_back(m-1); } int mst() { int ans = 0; sort(edges.begin(), edges.end()); for(int i = 0; i < m; i++) { Edge& e = edges[i]; int x = ufs.find(e.from), y = ufs.find(e.to); if(x != y) ufs.unin(x, y), ans += e.dist; } return ans; } }; struct TwoSAT { int n; vectorG[maxn*2]; bool mark[maxn*2]; int S[maxn*2], c; bool dfs(int x) { if (mark[x^1]) return false; if (mark[x]) return true; mark[x] = true; S[c++] = x; for (int i = 0; i < G[x].size(); i++) if (!dfs(G[x][i])) return false; return true; } void init(int n) { this->n = n; for (int i = 0; i < n*2; i++) G[i].clear(); memset(mark, 0, sizeof(mark)); } // x = xval or y = yval void add_clause(int x, int xval, int y, int yval) { x = x * 2 + xval; y = y * 2 + yval; G[x^1].push_back(y); G[y^1].push_back(x); } bool solve() { for(int i = 0; i < n*2; i += 2) if(!mark[i] && !mark[i+1]) { c = 0; if(!dfs(i)) { while(c > 0) mark[S[--c]] = false; if(!dfs(i+1)) return false; } } return true; } }; // 判定二分圖 bool bipartite(int u, int b) { for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if(bccno[v] != b) continue; if(color[v] == color[u]) return false; if(!color[v]) { color[v] = 3 - color[u]; if(!bipartite(v, b)) return false; } } return true; } // 雙聯(lián)通分量算法 stackS; int dfs(int u, int fa) { int lowu = pre[u] = ++dfs_clock; int child = 0; for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; Edge e = (Edge){u, v}; if(!pre[v]) { // 沒有訪問過v S.push(e); child++; int lowv = dfs(v, u); lowu = min(lowu, lowv); // 用后代的low函數(shù)更新自己 if(lowv >= pre[u]) { iscut[u] = true; bcc_cnt++; bcc[bcc_cnt].clear(); for(;;) { Edge x = S.top(); S.pop(); if(bccno[x.u] != bcc_cnt) { bcc[bcc_cnt].push_back(x.u); bccno[x.u] = bcc_cnt; } if(bccno[x.v] != bcc_cnt) { bcc[bcc_cnt].push_back(x.v); bccno[x.v] = bcc_cnt; } if(x.u == u && x.v == v) break; } } } else if(pre[v] < pre[u] && v != fa) { S.push(e); lowu = min(lowu, pre[v]); // 用反向邊更新自己 } } if(fa < 0 && child == 1) iscut[u] = 0; return lowu; } void find_bcc(int n) { memset(pre, 0, sizeof(pre)); memset(iscut, 0, sizeof(iscut)); memset(bccno, 0, sizeof(bccno)); dfs_clock = bcc_cnt = 0; for(int i = 0; i < n; i++) if(!pre[i]) dfs(i, -1); } struct Tarjan { vectorG[maxn]; int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt; stackS; void dfs(int u) { pre[u] = lowlink[u] = ++dfs_clock; S.push(u); for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if(!pre[v]) { dfs(v); lowlink[u] = min(lowlink[u], lowlink[v]); } else if(!sccno[v]) { // notice lowlink[u] = min(lowlink[u], pre[v]); } } if(lowlink[u] == pre[u]) { scc_cnt++; for(;;) { int x = S.top(); S.pop(); sccno[x] = scc_cnt; if(x == u) break; } } } void find_scc(int n) { dfs_clock = scc_cnt = 0; memset(sccno, 0, sizeof(sccno)); memset(pre, 0, sizeof(pre)); for(int i = 0; i < n; i++) if(!pre[i]) dfs(i); } }; struct TOPO { int n, m, d[maxn], d0[maxn]; vectoredges; vectorG[maxn]; void init(int n) { this->n = n; memset(d0, 0, sizeof(d0)); edges.clear(); for(int u = 1; u <= n; u++) G[u].clear(); } void AddEdge(int from, int to, int dist) { edges.push_back((Edge){to, dist}); m = edges.size(); G[from].push_back(m-1); d0[to]++; } int toposort() { queueQ; memset(d, 0, sizeof(d)); for(int u = 1; u <= n; u++) if(G[u].size() != 0 && !d0[u]) Q.push(u); int max_d = 0; while(!Q.empty()) { int u = Q.front(); Q.pop(); max_d = max(max_d, d[u]); // 最長路 for(int i = 0; i < G[u].size(); i++) { Edge& e = edges[G[u][i]]; d[e.to] = max(d[e.to], d[u] + e.dist); if(--d0[e.to] == 0) Q.push(e.to); } } return max_d; } }; // 二分圖最大基數(shù)匹配 struct Match { vectorG[maxn]; bool vis[maxn]; int dfs(int u) { for(int i = 0; i < G[u].size(); i++) { int v = G[u][i]; if(!vis[v]) { vis[v] = 1; if(y[v] == -1 || dfs(y[v])) { x[u] = v; y[v] = u; return 1; } } } return 0; } int match() { int ans = 0; memset(y, -1, sizeof(y)); for(int i = 1; i <= m; i++) { memset(vis, 0, sizeof(vis)); ans += dfs(i); } return ans; } }; // 最小環(huán) struct Floyed { int n; int G[maxn][maxn], f[maxn][maxn]; int floyed() { int ans = INF; for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) f[i][j] = G[i][j]; // 可以直接枚舉 k, i, j, 在計(jì)算 f 的值的同時(shí)更新 ans. // 即 : /* for(int k = 0; k < n; k++) { for(int i = 0; i < n; i++) if(G[i][k] != INF) for(int j = 0; j < n; j++) if(i != k && i != j && k != j) { ans = min(ans, f[i][j] + G[i][k] + G[k][j]); f[i][j] = min(f[i][j], f[i][k] + f[k][j]); } } */ // 也是種可行的做法 // 下面是優(yōu)化過的做法 : for(int k = 0; k < n; k++) { // 枚舉編號(hào)最大點(diǎn) for(int i = 0; i < k; i++) if(G[i][k] != INF) for(int j = i+1; j < k; j++) // 如果為有向邊, j 從 0 開始枚舉 ans = min(ans, f[i][j] + G[i][k] + G[k][j]); // 此時(shí) f[i][j] 一定沒有用 k 更新過 // 所以 f[i][j] 表示的路徑不過 k // 更新最短路 for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) f[i][j] = min(f[i][j], f[i][k] + f[k][j]); // 用 f[][] 而不是 G[][] 在更新答案 } return ans == INF ? -1 : ans; } }; // 無向圖歐拉路徑 struct Euler { int n; bool G[maxn][maxn], vis[maxn][maxn]; vectorans; void euler(int u) { for(int v = 0; v < n; v++) if(G[u][v] && !vis[u][v]) { vis[u][v] = vis[v][u] = 1; euler(v); ans.push_back((Edge){u, v}); } } int judge(int start) { euler(start); if(ans.size() == n && ans[0].to == ans[ans.size()-1].from) return 1; return 0; } }; struct LCA { int n; int fa[maxn]; // 父親數(shù)組 int cost[maxn]; // 和父親的費(fèi)用 int L[maxn]; // 層次(根節(jié)點(diǎn)層次為0) int anc[maxn][logmaxn]; // anc[p][i]是結(jié)點(diǎn)p的第2^i級(jí)父親。anc[i][0] = fa[i] int maxcost[maxn][logmaxn]; // maxcost[p][i]是i和anc[p][i]的路徑上的最大費(fèi)用 // 預(yù)處理,根據(jù)fa和cost數(shù)組求出anc和maxcost數(shù)組 void preprocess() { for(int i = 0; i < n; i++) { anc[i][0] = fa[i]; maxcost[i][0] = cost[i]; for(int j = 1; (1<< n; j++) anc[i][j] = -1; } for(int j = 1; (1<< n; j++) for(int i = 0; i < n; i++) if(anc[i][j-1] != -1) { int a = anc[i][j-1]; anc[i][j] = anc[a][j-1]; maxcost[i][j] = max(maxcost[i][j-1], maxcost[a][j-1]); } } // 求p到q的路徑上的最大權(quán) int query(int p, int q) { int tmp, log, i; if(L[p] < L[q]) swap(p, q); for(log = 1; (1 << log) <= L[p]; log++); log--; int ans = -INF; for(int i = log; i >= 0; i--) if (L[p] - (1 << i) >= L[q]) { ans = max(ans, maxcost[p][i]); p = anc[p][i]; } if (p == q) return ans; // LCA為p for(int i = log; i >= 0; i--) if(anc[p][i] != -1 && anc[p][i] != anc[q][i]) { ans = max(ans, maxcost[p][i]); p = anc[p][i]; ans = max(ans, maxcost[q][i]); q = anc[q][i]; } ans = max(ans, cost[p]); ans = max(ans, cost[q]); return ans; // LCA為fa[p](它也等于fa[q]) } }; // 固定根的最小樹型圖,鄰接矩陣寫法 struct MDST { int n; int w[maxn][maxn]; // 邊權(quán) int vis[maxn]; // 訪問標(biāo)記,僅用來判斷無解 int ans; // 計(jì)算答案 int removed[maxn]; // 每個(gè)點(diǎn)是否被刪除 int cid[maxn]; // 所在圈編號(hào) int pre[maxn]; // 最小入邊的起點(diǎn) int iw[maxn]; // 最小入邊的權(quán)值 int max_cid; // 最大圈編號(hào) void init(int n) { this->n = n; for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) w[i][j] = INF; } void AddEdge(int u, int v, int cost) { w[u][v] = min(w[u][v], cost); // 重邊取權(quán)最小的 } // 從s出發(fā)能到達(dá)多少個(gè)結(jié)點(diǎn) int dfs(int s) { vis[s] = 1; int ans = 1; for(int i = 0; i < n; i++) if(!vis[i] && w[s][i] < INF) ans += dfs(i); return ans; } // 從u出發(fā)沿著pre指針找圈 bool cycle(int u) { max_cid++; int v = u; while(cid[v] != max_cid) { cid[v] = max_cid; v = pre[v]; } return v == u; } // 計(jì)算u的最小入弧,入弧起點(diǎn)不得在圈c中 void update(int u) { iw[u] = INF; for(int i = 0; i < n; i++) if(!removed[i] && w[i][u] < iw[u]) { iw[u] = w[i][u]; pre[u] = i; } } // 根結(jié)點(diǎn)為s,如果失敗則返回false bool solve(int s) { memset(vis, 0, sizeof(vis)); if(dfs(s) != n) return false; memset(removed, 0, sizeof(removed)); memset(cid, 0, sizeof(cid)); for(int u = 0; u < n; u++) update(u); pre[s] = s; iw[s] = 0; // 根結(jié)點(diǎn)特殊處理 ans = max_cid = 0; for(;;) { bool have_cycle = false; for(int u = 0; u < n; u++) if(u != s && !removed[u] && cycle(u)) { have_cycle = true; // 以下代碼縮圈,圈上除了u之外的結(jié)點(diǎn)均刪除 int v = u; do { if(v != u) removed[v] = 1; ans += iw[v]; // 對(duì)于圈外點(diǎn)i,把邊i->v改成i->u(并調(diào)整權(quán)值);v->i改為u->i // 注意圈上可能還有一個(gè)v'使得i->v'或者v'->i存在,因此只保留權(quán)值最小的i->u和u->i for(int i = 0; i < n; i++) if(cid[i] != cid[u] && !removed[i]) { if(w[i][v] < INF) w[i][u] = min(w[i][u], w[i][v]-iw[v]); w[u][i] = min(w[u][i], w[v][i]); if(pre[i] == v) pre[i] = u; } v = pre[v]; } while(v != u); update(u); break; } if(!have_cycle) break; } for(int i = 0; i < n; i++) if(!removed[i]) ans += iw[i]; return true; } }; // 以下為網(wǎng)絡(luò)流 struct Dinic { int n, m, s, t; int first[maxm], next[maxm]; Edge edges[maxm]; bool vis[maxn]; int d[maxn], cur[maxn]; void init(int n, int s, int t) { this->n = n; this->m = 1; this->s = s; this->t = t; } void AddEdge(int u, int v, int cap) { edges[++m] = (Edge){u, v, cap, 0}; next[m] = first[u]; first[u] = m; edges[++m] = (Edge){v, u, 0, 0}; next[m] = first[v]; first[v] = m; } bool BFS() { memset(vis, 0, sizeof(vis)); queueQ; Q.push(s); vis[s] = 1; d[s] = 0; while(!Q.empty()) { int u = Q.front(); Q.pop(); for(int i = first[u]; i; i = next[i]) { Edge& e = edges[i]; if(!vis[e.to] && e.cap > e.flow) { vis[e.to] = 1; d[e.to] = d[u] + 1; Q.push(e.to); } } } return vis[t]; } int DFS(int u, int a) { if(u == t || a == 0) return a; int flow = 0, f; for(int& i = cur[u]; i; i = next[i]) { Edge& e = edges[i]; if(d[u] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap-e.flow))) > 0) { edges[i].flow += f; edges[i^1].flow -= f; flow += f; a -= f; if(a == 0) break; } } return flow; } int Maxflow() { int flow = 0; while(BFS()) { for(int u = 0; u < n; u++) cur[u] = first[u]; flow += DFS(s, INF); } return flow; } }; struct MCMF { int n, m, s, t; Edge edges[maxm]; int first[maxn], next[maxn]; int inq[maxn], d[maxn], p[maxn], a[maxn]; void init(int n, int s, int t) { this->n = n; this->m = 1; this->s = s; this->t = t; } void AddEdge(int u, int v, int cap, int cost) { edges[++m] = (Edge){u, v, cap, 0, cost}; next[m] = first[u]; first[u] = m; edges[++m] = (Edge){v, u, 0, 0, -cost}; next[m] = first[v]; first[v] = m; } bool BellmanFord(int& cost) { for(int i = 0; i < n; i++) d[i] = INF; memset(inq, 0, sizeof(inq)); d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF; queueQ; Q.push(s); while(!Q.empty()) { int u = Q.front(); Q.pop(); inq[u] = 0; for(int i = first[u]; i; i = next[i]) { Edge& e = edges[i]; if(e.cap > e.flow && d[e.to] > d[u] + e.cost) { d[e.to] = d[u] + e.cost; p[e.to] = i; a[e.to] = min(a[u], e.cap - e.flow); if(!inq[e.to]) { Q.push(e.to); inq[e.to] = 1; } } } } if(d[t] == INF) return false; cost += d[t] * a[t]; int u = t; while(u != s) { edges[p[u]].flow += a[t]; edges[p[u]^1].flow -= a[t]; u = edges[p[u]].from; } return true; } int Mincost() { int cost = 0; while(BellmanFord(cost)); return cost; } };
總結(jié)