一、Dijkstra 无负权图 O(mlogm)
#include <cstdio>
#include <cstring>
#include <queue>
#define max(a, b) (a > b ? a : b)
using namespace std;
const int N = 1e5 + 5, M = 1e5 + 5, INF = 0x3f3f3f3f;
struct E {
int v, w, next;
}e[M];
struct Node {
int v, d;
Node(int v, int d):v(v), d(d){}
bool operator < (const Node &w)const {
return d > w.d;
}
};
int n, m, len = 1, head[N], d[N];
bool vis[N];
void add(int u, int v, int w) {
e[len].v = v;
e[len].next = head[u];
e[len].w = w;
head[u] = len++;
}
void dijkstra(int u) {
memset(d, 0x3f, sizeof(d));
d[u] = 0;
priority_queue<Node> q;
q.push(Node(u, 0));
while (!q.empty()) {
u = q.top().v;
q.pop();
if (vis[u]) continue;
vis[u] = true;
for (int j = head[u]; j; j = e[j].next) {
int v = e[j].v;
int w = e[j].w;
if (!vis[v] && d[v] > d[u] + w) {
d[v] = d[u] +w;
q.push(Node(v, d[v]));
}
}
}
}
int main() {
scanf("%d%d", &n, &m);
int u, v, w;
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
}
dijkstra(1);
printf("%d\n", d[n] == INF ? -1 : d[n]);
return 0;
}
O(n2):
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1005, INF = 0x3f3f3f3f;
int t, n, m, u, v, w, g[N][N], d[N];
bool vis[N];
void djkstra() {
memset(vis, false, sizeof(vis));
memset(d, 0x3f, sizeof(d));
d[1] = 0;
for (int i = 1; i <= n; i++) {
int t = -1;
for (int j = 1; j <= n; j++) {
if (!vis[j] && (t == -1 || d[t] > d[j])) t = j;
}
vis[t] = true;
for (int j = 1; j <= n; j++) {
d[j] = min(d[j], d[t] + g[t][j]);
}
}
}
int main() {
memset(g, 0x3f, sizeof(g));
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
g[u][v] = g[v][u] = min(w, g[u][v]);
}
djkstra();
printf("%d\n", d[n]);
return 0;
}
二、Bellma_Ford 经过k条边的最短路 O(nm)
#include <cstdio>
#include <cstring>
#define min(a, b) (a > b ? b : a)
using namespace std;
const int N = 505, M = 1e4 + 5, INF = 0x3f3f3f3f;
struct E {
int u, v, w;
}e[M];
int n, m, k, len, d[N], last[N]; //last防止发生串联
void add(int u, int v, int w) {
e[++len].u = u;
e[len].v = v;
e[len].w = w;
}
void Bellman_Ford(int u) {
memset(d, 0x3f, sizeof(d));
d[u] = 0;
for (int i = 1; i <= k; i++) {
memcpy(last, d, sizeof(d)); //拷贝上一次的结果
for (int i = 1; i <= m; i++) {
int u = e[i].u;
int v = e[i].v;
int w = e[i].w;
d[v] = min(d[v], last[u] + w);
}
}
}
int main() {
scanf("%d%d%d", &n, &m, &k);
int u, v, w;
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
}
Bellman_Ford(1);
if (d[n] > INF / 2) printf("impossible");
else printf("%d", d[n]);
return 0;
}
三、SPFA O(km) ~ O(nm)
#include <cstdio>
#include <cstring>
#include <queue>
#define max(a, b) (a > b ? a : b)
using namespace std;
const int N = 1e5 + 5, M = 1e5 + 5, INF = 0x3f3f3f3f;
struct E {
int v, w, next;
}e[M];
struct Node {
int v, d;
Node(int v, int d):v(v), d(d){}
bool operator < (const Node &w)const {
return d > w.d;
}
};
int n, m, len = 1, head[N], d[N];
bool vis[N];
void add(int u, int v, int w) {
e[len].v = v;
e[len].next = head[u];
e[len].w = w;
head[u] = len++;
}
void spfa(int u) {
memset(d, 0x3f, sizeof(d));
d[u] = 0;
queue<int> q;
q.push(u);
while (!q.empty()) {
u = q.front();
q.pop();
vis[u] = false;
for (int j = head[u]; j; j = e[j].next) {
int v = e[j].v;
int w = e[j].w;
if (d[v] > d[u] + w) {
d[v] = d[u] + w;
if (!vis[v]) q.push(v), vis[v] = true;
}
}
}
}
int main() {
scanf("%d%d", &n, &m);
int u, v, w;
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
}
spfa(1);
if (d[n] == INF) printf("impossible");
else printf("%d", d[n]);
return 0;
}
- 判断负环
#include <cstdio>
#include <cstring>
#include <queue>
#define max(a, b) (a > b ? a : b)
using namespace std;
const int N = 1e5 + 5, M = 1e5 + 5, INF = 0x3f3f3f3f;
struct E {
int v, w, next;
}e[M];
struct Node {
int v, d;
Node(int v, int d):v(v), d(d){}
bool operator < (const Node &w)const {
return d > w.d;
}
};
int n, m, len = 1, head[N], d[N], cnt[N]; // cnt判断入队次数
bool vis[N];
void add(int u, int v, int w) {
e[len].v = v;
e[len].next = head[u];
e[len].w = w;
head[u] = len++;
}
bool spfa() {
queue<int> q;
for (int i = 1; i <= n; i++) q.push(i), vis[i] = true; //把所有点加进去
while (!q.empty()) {
int u = q.front();
q.pop();
vis[u] = false;
for (int j = head[u]; j; j = e[j].next) {
int v = e[j].v;
int w = e[j].w;
if (d[v] > d[u] + w) {
d[v] = d[u] + w;
if (!vis[v]) {
q.push(v);
vis[v] = true;
cnt[v]++;
if (cnt[v] > n) return true;
}
}
}
}
return false;
}
int main() {
scanf("%d%d", &n, &m);
int u, v, w;
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
}
if (spfa()) printf("Yes");
else printf("No");
return 0;
}
四、Floyd O(n^3)
#include <cstdio>
#include <cstring>
#define min(a, b) (a > b ? b : a)
using namespace std;
const int N = 205, INF = 0x3f3f3f3f;
int g[N][N], n, m , k, u, v, w;
void floyd() {
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]);
}
}
}
}
int main() {
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (i == j) g[i][j] = 0; //自环 直接删去 因为自环肯定是正边
else g[i][j] = INF;
}
}
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
g[u][v] = min(g[u][v], w);
}
floyd();
while (k--) {
scanf("%d%d", &u, &v);
if (g[u][v] > INF / 2) { //因为负权边的原因
printf("impossible\n");
} else {
printf("%d\n", g[u][v]);
}
}
return 0;
}
五、Prime O(n^2)
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 505, INF = 0x3f3f3f3f ;
int n, m, u, v, w, g[N][N], d[N];
bool vis[N];
int prime() {
int ans = 0;
memset(d, 0x3f, sizeof(d));
//1.遍历n个起点
for (int i = 0; i < n; i++) {
//2.选择一个点到集合的距离最短
int t = -1;
for (int j = 1; j <= n; j++) {
if (!vis[j] && (t == -1 || d[t] > d[j])) t = j;
}
//3.判断是否没有边 如果没有边返回INF
//第一个点不算
if (i && d[t] == INF) return INF;
//4.从这个点出发更新其他点到集合的最短距离 (其他点到集合的距离,t点到其他点的距离)
if (i) ans += d[t];
for (int j = 1; j <= n; j++) d[j] = min(d[j], g[t][j]);
vis[t] = true; //加入集合
}
return ans;
}
int main() {
scanf("%d%d", &n, &m);
memset(g, 0x3f, sizeof(g));
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &u, &v, &w);
g[u][v] = g[v][u] = min(g[u][v], w);
}
int t = prime();
if (t == INF) printf("impossible\n");
else printf("%d\n", t);
return 0;
}
六、Kruskal O(mlogm)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int M = 2e5 + 5, N = 1e5 + 5;
struct E {
int u, v, w;
bool operator < (const E&o)const {
return w < o.w;
}
} e[M];
int n, m, p[N];
int find(int x) {
return x == p[x] ? x : (p[x] = find(p[x]));
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
}
sort(e + 1, e + 1 + m);
for (int i = 1; i <= n; i++) p[i] = i;
//选择n - 1条最小的边
int cnt = 0, ans = 0;
for (int i = 1; i <= m; i++) {
int fx = find(e[i].u);
int fy = find(e[i].v);
if (fx != fy) {
cnt++;
p[fx] = fy;
ans += e[i].w;
}
if (cnt == n - 1) break;
}
if (cnt == n - 1) printf("%d\n", ans);
else printf("impossible\n");
return 0;
}
七、匈牙利 O(nm)
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 505, M = 1e5 + 5;
struct E {
int v, next;
} e[M];
int n1, n2, m, u, v, head[N], len = 1, mat[N];
bool vis[N];
void add(int u, int v) {
e[len].v = v;
e[len].next = head[u];
head[u] = len++;
}
bool find(int u) {
for (int j = head[u]; j; j = e[j].next){
int v = e[j].v;
if (!vis[v]) {
vis[v] = true;
if (mat[v] == 0 || find(mat[v])) {
mat[v] = u;
return true;
}
}
}
return false;
}
int main() {
scanf("%d%d%d", &n1, &n2, &m);
for (int i = 1; i <= m; i++) {
scanf("%d%d", &u, &v);
add(u, v);
}
int ans = 0;
for (int i = 1; i <= n1; i++) {
memset(vis, false, sizeof(vis));
if (find(i)) ans++;
}
printf("%d", ans);
return 0;
}