# 图论总结 Dijkstra Tarjan 最小生成树 二分图 最短路 强连通分量 双连通分量 Bellman-Ford SPFA 二分图染色 Kruskal Prim 网络流 二分图匹配 Dinic

``这周学些图论。``
``图论大概NOIP考的有这些算法：``

Dijkstra

SCC

BCC

Bipartite

Kruskal

(Prim)

Bellman-Ford

Dinic

``````#include <vector>
#include <queue>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 100050;
const int inf = 1e9;
struct edge{
int to, dist;
};
struct heap{
int d, u;
bool operator < (const heap& rhs) const {
return d > rhs.d;
}
};
vector<edge> G[maxn];
bool vis[maxn];
int dj[maxn], pre[maxn];
int n, m;

void dijkstra(int st) {
priority_queue<heap> Q;
for(int i = 0; i < n; i++) dj[i] = inf;
dj[st] = 0;
memset(vis, 0, sizeof(vis));
Q.push((heap){0, st});
while(!Q.empty()) {
heap j = Q.top(); Q.pop();
int u = j.u;
if(vis[u]) continue;
vis[u] = 1;
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i].to, w = G[u][i].dist;
if(dj[v] > dj[u] + w) {
dj[v] = dj[u] + w;
pre[v] = u;
Q.push((heap){dj[v], v});
}
}
}
}

int main() {
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++) {
int from, to, dist;
scanf("%d%d%d", &from, &to, &dist);
edge e;
e.to = to - 1; e.dist = dist;
G[from - 1].push_back(e);
}
dijkstra(0);
for(int i = 0; i < n; i++) printf("%d ", dj[i]);
return 0;
}``````

Dijkstra求最短路还可以加上一些限制。改一下到st距离的意义，然后对入队条件加一些限制即可。heap里两个元素不变。

SCC强连通分量

``````#include <iostream>
#include <vector>
#include <stack>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 100050;
vector<int> G[maxn];
stack<int> S;
int n, m, dcl, sccn;
int sccno[maxn], pre[maxn];

int getlow(int u) {
int lowu = pre[u] = ++dcl;
S.push(u);
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(!pre[v]) {
int lowv = getlow(v);
lowu = min(lowu, lowv);
}else if(!sccno[v]) lowu = min(lowu, pre[v]);
}
if(lowu == pre[u]) {
sccn++;
for(;;) {
int j = S.top(); S.pop();
sccno[j] = sccn;
if(u == j) break;
}
}
return lowu;
}
void find_scc() {
dcl = sccn = 0;
memset(sccno, 0, sizeof(sccno));
memset(pre, 0, sizeof(pre));
for(int i = 0; i < n; i++) if(!pre[i]) getlow(i);
}

int main() {
cin >> n >> m;
for(int i = 0; i < m; i++) {
int from, to;
cin >> from >> to;
G[from - 1].push_back(to - 1);
}
find_scc();
for(int i=0;i<n;i++)cout<<sccno[i]<<" ";
cout<<endl;
}``````

BCC双连通分量

``````#include <vector>
#include <stack>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn = 100050;
struct edge{
int from, to;
};
vector<int> G[maxn];
stack<edge> S;
int dcl, bccn, pre[maxn], bccno[maxn], iscut[maxn];
int n, m;

int getlow(int u, int fa) {
int lowu = pre[u] = ++dcl;
int child = 0;
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(!pre[v]) {
S.push((edge){u, v});
child++;
int lowv = getlow(v, u);
lowu = min(lowu, lowv);
if(lowv >= pre[u]) {
iscut[u] = 1;
bccn++;
for(;;) {
edge j = S.top(); S.pop();
bccno[j.from] = bccn;
bccno[j.to] = bccn;
if(j.from == u && j.to == v) break;
}
}
}else if(pre[v] < pre[u] && v != fa) {
S.push((edge){u, v});
lowu = min(lowu, pre[v]);
}
}
if(fa < 0 && child == 1) iscut[u] = 0;
return lowu;
}
void find_bcc() {
dcl = bccn = 0;
memset(pre, 0, sizeof(pre));
memset(bccno, 0, sizeof(bccno));
memset(iscut, 0, sizeof(iscut));
for(int i = 0; i < n; i++) if(!pre[i]) getlow(i, -1);
}

int main() {
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++) {
int from, to;
scanf("%d%d", &from, &to);
G[from - 1].push_back(to - 1);
G[to - 1].push_back(from - 1);
}
find_bcc();
for(int i = 0; i < n; i++) printf("%d ", bccno[i]);
printf("\n");
return 0;
}``````

Bipartite二分图染色

``````#include <vector>
#include <cstdio>
#include <iostream>
using namespace std;
const int maxn = 100050;
vector<int> G[maxn];
int col[maxn];
int n, m;
int a = 0, c;
do c = getchar(); while(c < 48 || c > 57);
do{a = a * 10 + c - 48; c = getchar();} while(c > 47 && c < 58);
return a;
}

int bipartite(int u) {
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i];
if(col[v] == col[u]) return 0;
if(!col[v]) {
col[v] = 3 - col[u];
if(!bipartite(v)) return 0;
}
}
return 1;
}

int main() {
for(int i = 0; i < m; i++) {
G[from].push_back(to);
//		G[to].push_back(from);
}
col[0] = 1;
cout << bipartite(0) << endl;
for(int i = 0; i < n; i++) cout << col[i] << " ";
cout << endl;
return 0;
}``````

Kruskal

Dinic

``````#include <vector>
#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 100050;
const int maxm = 1000050;
const int inf = 1e9+7;
struct edge{
int from, to, cap, flow;
};
vector<edge> E;
vector<int> G[maxn];
int n, m, s, t;
int cur[maxn], d[maxn], vis[maxn];

void addedge(int from, int to, int cap) {
E.push_back((edge){from, to, cap, 0});
E.push_back((edge){to, from, 0, 0});
int m = E.size();
G[from].push_back(m-2);
G[to].push_back(m-1);
}

int enlevel() {
memset(vis, 0, sizeof(vis));
queue<int> Q;
Q.push(s);
d[s] = 0;
vis[s] = 1;
while(!Q.empty()) {
int x = Q.front(); Q.pop();
for(int i = 0; i < G[x].size(); i++) {
edge& e = E[G[x][i]];
if(!vis[e.to] && e.cap > e.flow) {
vis[e.to] = 1;
d[e.to] = d[x] + 1;
Q.push(e.to);
}
}
}
return vis[t];
}
int large(int x, int a) {
if(x == t || a == 0) return a;
int flow = 0, f;
for(int& i = cur[x]; i < G[x].size(); i++) {
edge& e = E[G[x][i]];
if(d[x] + 1 == d[e.to]) if(f = large(e.to, min(a, e.cap-e.flow)) > 0) {
e.flow += f;
E[G[x][i^1]].flow -= f;
flow += f;
a -= f;
if(a == 0) break;
}
}
return flow;
}
int maxflow() {
int flow = 0;
while(enlevel()) {
memset(cur, 0, sizeof(cur));
flow += large(s, inf);
}
return flow;
}

int main() {
cin >> n >> m >> s >> t;
for(int i = 0; i < m; i++) {
int from, to, cap;
cin >> from >> to >> cap;
addedge(from - 1, to - 1, cap - 1);
}
cout << maxflow();
return 0;
}``````

原文作者：Bellman - ford算法
原文地址: https://blog.csdn.net/myjs999/article/details/77994846
本文转自网络文章，转载此文章仅为分享知识，如有侵权，请联系博主进行删除。