【模板】圖論演算法模板(持更)
阿新 • • 發佈:2019-02-20
圖論
圖論是個大板塊,建模在圖論中佔有很重要的地位,至於演算法就是理解之後程式碼多敲敲,具體的架構還是差不多的。
圖論大概有3個級別,第一級別就是沒有邊權的圖,用於遍歷或者強連通SCC跑一波等等;第二級別就是有邊權的,這下演算法多了,各種最短路和最小生成樹都有了,一二級別有時候可以合併,遍歷時沒有邊權實際上邊權就是1;然後第三級別就是有流量(dalao們的網路流),當然還有各種變種,比如說加個費用啊什麼的。
第一級別
SCC_Tarjan
struct Graph {
struct edgetype {
int to, next;
};
int n, dfs_clock, scc_cnt;
std::vector< edgetype > edge;
std::vector< int > head, dfn, low, scc;
std::stack< int > Stack;
Graph() : n(0), edge(0), head(0), dfn(0), low(0), scc(0) {}
Graph(int n) : n(n), head(n + 1, -1), dfn(n + 1), low(n + 1), scc(n + 1) {}
void AddEdge(int from, int to) {
edge.push_back((edgetype){to, head[from]});
head[from] = edge.size() - 1;
}
void DFS(int u) {
dfn[u] = low[u] = ++dfs_clock;
Stack.push(u);
int v;
for (int i = head[u]; i != -1; i = edge[i].next) {
v = edge[i].to;
if (!dfn[i]) {
DFS(v);
low[u] = min(low[u], dfn[v]);
}
else if (!scc[v])
low[u] = min(low[u], low[v]);
}
if (low[u] == dfn[u]) {
scc_cnt++;
do {
v = Stack.top();
Stack.pop();
scc[v] = scc_cnt;
} while (u != v);
}
}
int Get_SCC() {
dfs_clock = scc_cnt = 0;
while (!Stack.empty()) Stack.pop();
for (int i = 1; i <= n; i++)
if (!dfn[i])
DFS(i);
return scc_cnt;
}
};
第二級別
由於分塊比較多,我直接按演算法全部給出了。
SPFA
struct Graph {
struct edgetype {
int to, next, dist;
};
int n;
std::vector< int > head;
std::vector< long long > dist;
std::vector< edgetype > edge;
std::vector< bool > inQ;
std::queue< int > Q;
Graph() : n(0), head(0), dist(0), edge(0), inQ(0) {}
Graph(int n, ) : n(n), head(n + 1, -1), dist(n + 1), inQ(n + 1) {}
void AddEdge(int from, int to, int dist) {
edge.push_back((edgetype){to, head[from], dist});
head[from] = edge.size() - 1;
}
void SSSP(int s) {
dist.assign(n + 1, 0x3f3f3f3f);
inQ.assign(n + 1, false);
while (!Q.empty()) Q.pop();
Q.push(s); dist[s] = 0; inQ[s] = true;
while (!Q.empty()) {
int u = Q.front(); Q.pop(); inQ[u] = false;
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if (dist[v] > dist[u] + edge[i].dist) {
dist[v] = dist[u] + edge[i].dist;
if (!inQ[v]) {
Q.push(v);
inQ[v] = true;
}
}
}
}
}
long long Distance(int s, int t) {
SSSP(s);
return dist[t];
}
};
Dijkstra
struct Graph {
struct EdgeType {
int to, next, dist;
};
struct HeapNode {
int point;
long long dist;
bool operator < (const HeapNode& rhs) const {
return dist > rhs.dist;
}
};
int n;
std::vector< int > head;
std::vector< long long >dist;
std::vector< bool > done;
std::vector< EdgeType > edge;
std::priority_queue< HeapNode > Q;
Graph() : n(0), head(0), dist(0), done(0), edge(0) {}
Graph(int n) : n(n), head(n + 1, -1), dist(n + 1), done(n + 1) {}
void AddEdge(int from, int to, int dist) {
edge.push_back((EdgeType){to, head[from], dist});
head[from] = edge.size() - 1;
}
void SSSP(int s) {
dist.assign(n + 1, 0x3f3f3f3f);
done.assign(n + 1, false);
while (!Q.empty()) Q.pop();
Q.push((HeapNode){s, 0}); dist[s] = 0;
while (!Q.empty()) {
HeapNode node = Q.top();
Q.pop();
if (done[node.point]) continue;
int u = node.point;
done[u] = true;
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if (dist[v] > dist[u] + edge[i].dist) {
dist[v] = dist[u] + edge[i].dist;
Q.push((HeapNode){v, dist[v]});
}
}
}
}
long long Distance(int s, int t) {
SSSP(s);
return dist[t];
}
};
Kruskal
struct Graph {
struct edgetype {
int from, to, dist;
bool operator < (const edgetype& rhs) const {
return dist < rhs.dist;
}
};
int n;
std::vector< edgetype > edge;
std::vector< int > f;
Graph() : n(0), edge(0), f(0) {}
Graph(int n) : n(n), f(n + 1) {}
void AddEdge(int from, int to, int dist) {
edge.push_back((edgetype){from, to, dist});
}
inline int FindRoot(int x) {
return f[x] == x ? x : f[x] = FindRoot(f[x]);
}
long long MST() {
int num = 0;
long long ans = 0;
for (int i = 1; i <= n; i++) f[i] = i;
sort(edge.begin(), edge.end());
for (unsigned int i = 0; i < edge.size(); i++) {
int fu = FindRoot(edge[i].from);
int fv = FindRoot(edge[i].to);
if (fu != fv) {
f[fu] = fv;
ans += edge[i].dist;
if (++num == n - 1) break;
}
}
return ans;
}
};
Prim
struct Graph {
struct edgetype {
int to, next, dist;
};
struct heapnode {
int point, dist;
bool operator < (const heapnode& rhs) const {
return dist > rhs.dist;
}
};
int n;
std::vector< int > head, dist;
std::vector< edgetype > edge;
std::priority_queue< heapnode > Q;
Graph() : n(0), head(0), dist(0), edge(0) {}
Graph(int n) : n(n), head(n + 1, -1), dist(n + 1) {}
inline void AddEdge(int from, int to, int dist) {
edge.push_back((edgetype){to, head[from], dist});
head[from] = edge.size() - 1;
}
long long MST() {
long long ans = 0;
dist.assign(n + 1, 0x3f3f3f3f);
while (!Q.empty()) Q.pop();
Q.push((heapnode){1, 0});
dist[1] = 0;
while (!Q.empty()) {
int u = Q.top().point;
Q.pop();
ans += dist[u];
dist[u] = 0;
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if (dist[v] > edge[i].dist) {
dist[v] = edge[i].dist;
Q.push((heapnode){v, dist[v]});
}
}
}
return ans;
}
};
Negative_Cycle
struct Graph {
struct edgetype {
int to, next, dist;
};
int n;
std::vector< int > head, dist;
std::vector< edgetype > edge;
std::vector< bool > visit;
Graph() : n(0), head(0), dist(0), edge(0), visit(0) {}
Graph(int n) :n(n), head(n + 1, -1), dist(n + 1), visit(n + 1) {}
void AddEdge(int from, int to, int dist) {
edge.push_back((edgetype){to, head[from], dist});
head[from] = edge.size() - 1;
}
void Negative_Cycle_Search(bool& exist, int u) {
if (exist) return;
visit[u] = true;
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if (dist[v] > dist[u] + edge[i].dist) {
dist[v] = dist[u] + edge[i].dist;
if (visit[v]) {
exist = true;
return;
}
Negative_Cycle_Search(exist, v);
}
}
visit[u] = false;
}
bool Negative_Cycle() {
dist.assign(n + 1, 0);
visit.assign(n + 1, false);
bool exist = false;
for (int i = 1; i <= n && !exist; i++)
Negative_Cycle_Search(exist, i);
return exist;
}
};
第三級別
最大流
連續最短增廣路(Dinic)
struct Graph {
static const int infty = 0x7f7f7f7f;
struct edgetype {
int to, next, flow, cap;
};
int n, s, t;
std::vector< edgetype > edge;
std::vector< bool > visit;
std::vector< int > head, d, cur;
std::queue< int > Q;
Graph() : n(0), edge(0), visit(0), head(0), d(0), cur(0) {}
Graph(int n) : n(n), visit(n + 1), head(n + 1, -1), d(n + 1), cur(n + 1) {}
void AddEdge(int from, int to, int cap) {
edge.push_back((edgetype){to, head[from], 0, cap});
head[from] = edge.size() - 1;
edge.push_back((edgetype){from, head[to], 0, 0});
head[to] = edge.size() - 1;
}
bool BFS() {
visit.assign(n + 1, false);
d.assign(n + 1, 0);
while (!Q.empty()) Q.pop();
Q.push(s); visit[s] = true;
while (!Q.empty()) {
int u = Q.front(); Q.pop();
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if (!visit[v] && edge[i].flow < edge[i].cap) {
visit[v] = true;
d[v] = d[u] + 1;
Q.push(v);
}
}
}
return visit[t];
}
long long DFS(int u, int alpha) {
if (u == t || alpha == 0) return alpha;
long long flow = 0, f;
for (int& i = cur[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if (d[u] + 1 == d[v] && (f = DFS(v, min(alpha, edge[i].cap - edge[i].flow))) > 0) {
edge[i].flow += f; edge[i ^ 1].flow -= f; flow += f; alpha -= f;
if (alpha == 0) break;
}
}
return flow;
}
long long Maxflow(int s, int t) {
this->s = s; this->t = t;
long long maxflow = 0;
while (BFS()) {
cur.assign(head.begin(), head.end());
maxflow += DFS(s, infty);
}
return maxflow;
}
};
一般預流推進
struct Graph {
static const int infty = 0x7f7f7f7f;
struct edgetype {
int to, next, flow, cap;
};
int n, s, t;
std::vector< edgetype > edge;
std::vector< int > head, h, excess;
std::queue< int > Q;
Graph() : n(0), edge(0), head(0), h(0), excess(0) {}
Graph(int n) : n(n), head(n + 1, -1), h(n + 1), excess(n + 1) {}
void AddEdge(int from, int to, int cap) {
edge.push_back((edgetype){to, head[from], 0, cap});
head[from] = edge.size() - 1;
edge.push_back((edgetype){from, head[to], 0, 0});
head[to] = edge.size() - 1;
}
void Push(int u, long long& maxflow) {
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
int f = min(edge[i].cap - edge[i].flow, excess[u]);
if (f > 0 && (u == s || h[u] == h[v] + 1)) {
edge[i].flow += f; edge[i ^ 1].flow -= f;
excess[u] -= f; excess[v] += f;
if (v == t) maxflow += f;
else if (v != s) Q.push(v);
}
}
}
void Relabel(int u) {
if (u != s && u != t && excess[u] > 0) h[u]++, Q.push(u);
}
long long Maxflow(int s, int t) {
this->s = s; this->t = t;
long long maxflow = 0;
excess.assign(n + 1, 0);
h.assign(n + 1, 0); h[s] = n;
excess[s] = infty; excess[t] = -infty;
Q.push(s);
while (!Q.empty()) {
int u = Q.front();
Q.pop();
Push(u, maxflow);
Relabel(u);
}
return maxflow;
}
};
最大標號預流推進
struct Graph {
static const int infty = 0x7f7f7f7f;
struct edgetype {
int to, next, flow, cap;
};
struct node {
int u, d;
bool operator < (const node& rhs) const {
return d < rhs.d;
}
};
int n, s, t;
std::vector< edgetype > edge;
std::vector< int > head, h, excess;
std::priority_queue< node > Q;
Graph() : n(0), edge(0), head(0), h(0), excess(0) {}
Graph(int n) : n(n), head(n + 1, -1), h(n + 1), excess(n + 1) {}
void AddEdge(int from, int to, int cap) {
edge.push_back((edgetype){to, head[from], 0, cap});
head[from] = edge.size() - 1;
edge.push_back((edgetype){from, head[to], 0, 0});
head[to] = edge.size() - 1;
}
void Push(int u, long long& maxflow) {
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
int f = min(edge[i].cap - edge[i].flow, excess[u]);
if (f > 0 && (u == s || h[u] == h[v] + 1)) {
edge[i].flow += f; edge[i ^ 1].flow -= f;
excess[u] -= f; excess[v] += f;
if (v == t) maxflow += f;
else if (v != s) Q.push((node){v, h[v]});
}
}
}
void Relabel(int u) {
if (u != s && u != t && excess[u] > 0) h[u]++, Q.push((node){u, h[u]});
}
long long Maxflow(int s, int t) {
this->s = s; this->t = t;
long long maxflow = 0;
excess.assign(n + 1, 0);
h.assign(n + 1, 0); h[s] = n;
excess[s] = infty; excess[t] = -infty;
Q.push((node){s, n});
while (!Q.empty()) {
int u = Q.top().u;
Q.pop();
Push(u, maxflow);
Relabel(u);
}
return maxflow;
}
};
最小費用最大流
struct Graph {
static const int infty = 0x7f7f7f7f;
struct edgetype {
int to, next, flow, cap, cost;
};
int n, s, t;
std::vector< edgetype > edge;
std::vector< bool > inQ;
std::vector< int > head, dist, path;
std::queue< int > Q;
Graph() : n(0), edge(0), inQ(0), head(0), dist(0), path(0) {}
Graph(int n) : n(n), inQ(n + 1), head(n + 1, -1), dist(n + 1), path(n + 1) {}
void AddEdge(int from, int to, int cap, int cost) {
edge.push_back((edgetype){to, head[from], 0, cap, cost});
head[from] = edge.size() - 1;
edge.push_back((edgetype){from, head[to], 0, 0, -cost});
head[to] = edge.size() - 1;
}
bool FindPath() {
dist.assign(n + 1, infty);
inQ.assign(n + 1, false);
path.assign(n + 1, -1);
while (!Q.empty()) Q.pop();
Q.push(s); dist[s] = 0; inQ[s] = true;
while (!Q.empty()) {
int u = Q.front(); Q.pop(); inQ[u] = false;
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if (edge[i].flow < edge[i].cap && dist[v] > dist[u] + edge[i].cost) {
dist[v] = dist[u] + edge[i].cost; path[v] = i;
if (!inQ[v]) {
Q.push(v);
inQ[v] = true;
}
}
}
}
return path[t] != -1;
}
void Argument(long long& Maxflow, long long& Mincost) {
long long alpha = infty;
for (int i = path[t]; i != -1; i = path[edge[i ^ 1].to])
alpha = min(alpha, edge[i].cap - edge[i].flow);
Maxflow += alpha; Mincost += dist[t] * alpha;
for (int i = path[t]; i != -1; i = path[edge[i ^ 1].to]) {
edge[i].flow += alpha;
edge[i ^ 1].flow -= alpha;
}
}
std::pair< long long, long long > MincostMaxflow(int s, int t) {
this->s = s; this->t = t;
long long Maxflow = 0, Mincost = 0;
while (FindPath())
Argument(Maxflow, Mincost);
return std::make_pair(Maxflow, Mincost);
}
};
這也要慢慢來,,,總結總是需要時間的