一、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;
}