一句話圖論演算法_8種
阿新 • • 發佈:2019-01-04
一句話Dijkstra演算法
從源點開始更新鄰邊,遍歷到達其最近的點,以其作為新源點,重複操作直到所有點更新完畢。
#include <iostream>
#include <vector>
using namespace std;
struct Node {
int to, val;
Node (int t, int v) : to(t), val(v) {}
};
const int maxn = 10005;
int n, m;
vector<Node> G[maxn];
int vis[maxn] = {}, dis[maxn];
void Dijkstra()
{
dis[1] = 0;
for (int i = 1; i <= n; ++i) {
int u = -1, _min = 0x3f3f3f3f;
for (int j = 1; j <= n; ++j) {
if (!vis[j] && _min > dis[j]) {
_min = dis[j];
u = j;
}
}
if (u == -1) break ;
vis[u] = true;
for (int j = 0; j < G[u].size(); ++j) {
int v = G[u][j].to, d = G[u][j].val;
dis[v] = min(dis[v], dis[u] + d);
}
}
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; ++i)
dis[i] = 0x3f3f3f3f;
for (int i = 0; i < m; ++i) {
int from, to, val;
cin >> from >> to >> val;
G[from].push_back(Node(to, val));
G[to].push_back(Node(from, val));
}
Dijkstra();
for (int i = 1; i <= n; ++i)
cout << dis[i] << ' ';
}
一句話SPFA演算法
一條邊當且僅當有和他相連的邊更新後它才會更新,使用佇列不斷找出這樣的邊,直到無法找出
#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
struct Node {
int to, val;
Node (int t, int v): to(t), val(v) {}
};
const int maxn = 10005;
const int INF = 0x3f3f3f3f;
int n, m;
vector<Node> G[maxn];
int dis[maxn];
bool inq[maxn] = {};
void SPFA()
{
dis[1] = 0;
queue<int> Q;
Q.push(1);
inq[1] = true;
while (!Q.empty()) {
int now = Q.front();
Q.pop();
inq[now] = false;
for (int i = 0; i < G[now].size(); ++i) {
int u = now;
int v = G[now][i].to, d = G[now][i].val;
if (dis[v] > dis[u] + d) {
dis[v] = dis[u] + d;
if (!inq[v]) {
Q.push(v);
inq[v] = true;
}
}
}
}
}
int main()
{
memset(dis, 0x3f, sizeof(dis));
cin >> n >> m;
for (int i = 0; i < m; ++i) {
int from, to, val;
cin >> from >> to >> val;
G[from].push_back(Node(to, val));
G[to].push_back(Node(from, val));
}
SPFA();
for (int i = 1; i <= n; ++i)
cout << dis[i] << ' ';
}
一句話Kruskal演算法
給邊按權值從小到大排序,依次找出使邊不成環的所有邊,所構成圖即為最小生成樹。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
struct Edge {
int from, to, cost;
Edge (int f, int t, int c): from(f), to(t), cost(c) {}
};
const int maxn = 10005;
const int INF = 0x3f3f3f3f;
int n, m;
vector<Edge> edge;
vector<int> ans;
int father[maxn];
bool cmp(Edge x, Edge y)
{
return x.cost < y.cost;
}
void init()
{
for (int i = 1; i <= n; ++i)
father[i] = i;
}
int find(int x)
{
return x == father[x] ? x : father[x] = find(father[x]);
}
void Kruskal()
{
sort(edge.begin(), edge.end(), cmp);
for (size_t i = 0; i < edge.size(); ++i) {
int x = find(edge[i].from), y = find(edge[i].to);
if (x != y) {
father[x] = y;
ans.push_back(edge[i].cost);
}
}
}
int main()
{
cin >> n >> m;
init();
for (int i = 0; i < m; ++i) {
int from, to, cost;
cin >> from >> to >> cost;
edge.push_back(Edge(from, to, cost));
}
Kruskal();
for (int i = 0; i < ans.size(); ++i)
cout << ans[i] << ' ';
}
一句話Prim演算法
類似Dijkstra演算法,從源點出發,更新其鄰邊所連點,找到最短距離點,加入點集作為源點集,重複步驟直到所有點新增完畢
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
struct Node {
int to, cost;
Node (int t, int c) : to(t), cost(c) {}
};
const int maxn = 10005;
const int INF = 0x3f3f3f3f;
int n, m;
int dis[maxn] = {};
bool vis[maxn] = {};
vector<Node> G[maxn];
vector<int> ans;
void Prim()
{
dis[1] = 0;
for (int i = 1; i <= n; ++i) {
int u = -1, _min = 0x3f3f3f3f;
for (int j = 1; j <= n; ++j) {
if (!vis[j] && dis[j] < _min) {
_min = dis[j];
u = j;
}
}
if (u == -1) break;
vis[u] = true;
ans.push_back(_min);
for (size_t j = 0; j < G[u].size(); ++j) {
int v = G[u][j].to, d = G[u][j].cost;
dis[v] = min(dis[v], d);
}
}
}
int main()
{
cin >> n >> m;
memset(dis, 0x3f, sizeof(dis));
for (int i = 0; i < m; ++i) {
int from, to, cost;
cin >> from >> to >> cost;
G[from].push_back(Node(to, cost));
G[to].push_back(Node(from, cost));
}
Prim();
for (size_t i = 1; i < ans.size(); ++i)
cout << ans[i] << ' ';
}
一句話Tarjan演算法
新時間戳遇上了舊時間戳,就連成了環,dfn和low相同,則為環(或單點)的起點,維護dfn和low是要點。
tip:單向圖
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
const int maxn = 10005;
int n, m;
bool ins[maxn] = {};
vector<int> G[maxn];
stack<int> S;
int dfn[maxn] = {}, low[maxn];
int index = 0, ans = 0;
void tarjan(int u)
{
S.push(u);
ins[u] = true;
dfn[u] = low[u] = ++index;
for (size_t i = 0; i < G[u].size(); ++i) {
int v = G[u][i];
if (dfn[v] == 0) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if (ins[v]) low[u] = min(low[u], low[v]);
}
if (dfn[u] == low[u]) {
ans++;
int now;
do {
now = S.top();
S.pop();
ins[now] = false;
cout << now << ' ';
} while (now != u);
cout << endl;
}
}
int main()
{
cin >> n >> m;
for (int i = 0; i < m; ++i) {
int from, to;
cin >> from >> to;
G[from].push_back(to); // 有向圖
}
for (int i = 1; i <= n; ++i) {
if (!dfn[i]) tarjan(i);
}
cout << "ans = " << ans << endl;
}
一句話Euler迴路演算法
斷奇偶,一點出,棧結構,末尾入,走去邊,倒著輸。
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
const int maxn = 1005;
int n, m;
bool G[maxn][maxn] = {};
stack<int> S;
void Euler(int u)
{
cout << "u = " << u << endl;
for (size_t i = 1; i <= n; ++i) {
if (G[u][i]) {
G[u][i] = G[i][u] = false;
Euler(i);
}
}
S.push(u);
}
int main()
{
cin >> n >> m;
for (int i = 0; i < m; ++i) {
int from, to;
cin >> from >> to;
G[from][to] = G[to][from] = true;
}
Euler(4);
while (!S.empty()) {
cout << S.top() << ' ';
S.pop();
}
}
一句話floyd演算法
遍歷每個點作為中間結點,如果可以以此點更新兩鄰點,則更新。
#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 1003;
int n, m;
int G[maxn][maxn] = {};
int main()
{
memset(G, 0x3f, sizeof(G));
cin >> n >> m;
for (int i = 1; i <= n; ++i)
G[i][i] = 0;
for (int i = 0; i < m; ++i) {
int from, to, cost;
cin >> from >> to >> cost;
G[from][to] = G[to][from] = cost;
}
for (int k = 1; k <= n; ++k) {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
G[i][j] = min(G[i][j], G[i][k] + G[k][j]);
}
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j)
cout << G[i][j] << ' ';
cout << endl;
}
}
一句話DAG最長路演算法
預知後事如何,請從前事算起,取最大值也。
#include <iostream>
#include <vector>
using namespace std;
const int maxn = 1005;
int n, m;
int G[maxn][maxn] = {};
int dis[maxn] = {};
int DAG(int u)
{
if (dis[u]) return dis[u];
for (int i = 1; i <= n; ++i) {
if (G[i][u]) {
dis[u] = max(dis[u], DAG(i) + G[i][u]);
}
}
return dis[u];
}
int main()
{
cin >> n >> m;
for (int i = 0; i < m; ++i) {
int from, to, cost;
cin >> from >> to >> cost;
G[from][to] = cost;
}
DAG(4);
for (int i = 1; i <= 5; ++i) {
cout << dis[i] << ' ';
}
cout << endl;
}