欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

备战NOIP——模板复习10

程序员文章站 2022-03-23 10:53:12
...

这里只有模板,并不作讲解,仅为路过的各位做一个参考以及用做自己复习的资料,转载注明出处。

最短路算法

Dijkstra + 堆优化

/*Copyright: Copyright (c) 2018
*Created on 2018-10-28  
*Author: 十甫
*Version 1.0 
*Title: Dijkstra + heap
*Time: 10 mins
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 10005;
const int maxm = 10005;

int head[maxn];
struct edge {
	int to, val, next;
} data[maxm * 2];
inline void add_edge(int from, int to, int val, int i) {
	data[i] = (edge) {to, val, head[from]};
	head[from] = i;
}
int n, m;
int dis[maxn];
bool vis[maxn];
struct node {
	int dist, ord;
	bool operator < (const node cmp) const {
		return dist > cmp.dist;
	}
};
void Dij(int p) {
	memset(dis, 0x3f, sizeof(dis));
	memset(vis, false, sizeof(vis));
	dis[p] = 0;
	priority_queue <node> q;
	q.push((node) {vis[p], p});
	for(int i = 1;i < n;i++) {
		while(vis[q.top().ord]) q.pop();
		node tmp = q.top();
		int u = tmp.ord;
		q.pop();
		vis[u] = true;
		for(int i = head[u];i;i = data[i].next) {
			int v = data[i].to, k = data[i].val;
			if(dis[v] > dis[u] + k) {
				dis[v] = dis[u] + k;
				q.push((node) {dis[v], v});
			}
		}
	}
}

int main() {
	scanf("%d%d", &n, &m);
	for(int i = 1;i <= m;i++) {
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		add_edge(a, b, c, i), add_edge(b, a, c, i + m);
	}
	int p;
	scanf("%d", &p);
	Dij(p);
	for(int i = 1;i <= n;i++) {
		printf("%d ", dis[i]);
	}
	printf("\n");
	return 0;
}

Floyd

/*Copyright: Copyright (c) 2018
*Created on 2018-10-28  
*Author: 十甫
*Version 1.0 
*Title: Floyd
*Time: 4 mins
*/
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int size = 605;
inline int Min(int a, int b) {
	return a < b ? a : b;
}

int n, m, dis[size][size];
void Floyd() {
	for(int k = 1;k <= n;k++) {
		for(int i = 1;i <= n;i++) {
			for(int j = 1;j <= n;j++) {
				dis[i][j] = Min(dis[i][j], dis[i][k] + dis[k][j]);
			}
		}
	}
}

int main() {
	scanf("%d%d", &n, &m);
	memset(dis, 0x3f, sizeof(dis));
	for(int i = 1;i <= n;i++) {
		dis[i][i] = 0;
	}
	for(int i = 1;i <= m;i++) {
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		dis[a][b] = dis[b][a] = Min(dis[a][b], c);
	}
	Floyd();
	int q;
	scanf("%d", &q);
	while(q--) {
		int a, b;
		scanf("%d%d", &a, &b);
		printf("%d\n", dis[a][b]);
	}
	return 0;
}

SPFA

/*Copyright: Copyright (c) 2018
*Created on 2018-10-28  
*Author: 十甫
*Version 1.0 
*Title: SPFA
*Time: 7 mins
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int maxn = 10005;
const int maxm = 10005;

int head[maxn];
struct edge {
	int to, val, next;
} data[maxm * 2];
inline void add_edge(int from, int to, int val, int i) {
	data[i] = (edge) {to, val, head[from]};
	head[from] = i;
}
int n, m, dis[maxn];
bool vis[maxn];
void SPFA(int p) {
	memset(dis, 0x3f, sizeof(dis));
	memset(vis, false, sizeof(vis));
	dis[p] = 0, vis[p] = true;
	queue <int> q;
	q.push(p);
	while(!q.empty()) {
		int u = q.front();
		q.pop();
		for(int i = head[u];i;i = data[i].next) {
			int v = data[i].to, k = data[i].val;
			if(dis[v] > dis[u] + k) {
				dis[v] = dis[u] + k;
				if(!vis[v]) q.push(v);
			}
		}
		vis[u] = false;
	}
}

int main() {
	scanf("%d%d", &n, &m);
	for(int i = 1;i <= m;i++) {
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		add_edge(a, b, c, i), add_edge(b, a, c, i + m);
	}
	int p;
	scanf("%d", &p);
	SPFA(p);
	for(int i = 1;i <= n;i++) {
		printf("%d ", dis[i]);
	}
	printf("\n");
	return 0;
}

如果图包含负环的话,可以利用SPFA判断负环, 具体做法参考@forever_dreams 的Blog


用 cnt[ i ] 表示从起点(假设就是 1)到 i 的最短距离包含点的个数,初始化 cnt[ 1 ] = 1,那么当我们能够用点 u 松弛点 v 时,松弛时同时更新 cnt[ v ] = cnt[ u ] + 1,若发现此时 cnt[ v ] > n,那么就存在负环
原文链接:  SPFA判负环


相关标签: 最短路 图论