最短路 BellmanFord SPFA floyd

今天学习了几个最短路的算法。

第一个:BellmanFord
有负权回路不一定有最短路。
dis[b] <= dis[a] + w
图的存储比较随意,可以用结构体存储。

用到的全局变量:

const int M = 10021;
int backup[M]; // 前一组dis数据
struct Edge { // 图的存储;
	int a,b,c; // a---> b 权重 w
}edges[M];
int dis[M]; // 距离

int BellmanFord() {
	memset(dis,0x3f,sizeof(dis));
	for(int i = 0; i < k; ++i) { // 小于等于前i个边之和
		memcpy(backup, dis, sizeof(dis) );
		for(int j = 0; j < n; ++j) {
			int a = edges[j].a, b = edges[j].b, c = edges[j].c;
			dis[b] = min(dis[b], dis[a] + c)		
		}
	}
	if(dis[n] > 0x3f3f3f3f / 2) return -1; // 防止无穷加无穷
	return dis[n];
}

int main() 
{
	int n, m;
	cin>>n>>m;
	for(int i = 0; i < m; ++i) {cin>>a>>b>>m;edges[i] = {a,b,c} }
	int t = BellmanFord();
}

SPFA算法;
根据BellmanFord算法的三角不等式改进
类bfs
用邻接表
用到的全局变量:
h[] e[] ne[] dis[] st[] w[] st[] idx

增添函数

void add(int a, int b, int ww) {
	e[idx] = b, ne[idx] = h[a], w[idx] = ww, h[a] = idx++;
}

代码实现SPFA:

memset(dis, 0x3f, sizeof(dis) );
queue<int> q;
dis[1] = 1;
q.push(1);
st[1] = true;
while(q.size() ) {
	int t = q.front();
	q.pop();
	st[t] = false;
	for(int i = h[t]; i != -1; i = ne[i] ) {
		int j = e[i];
		if(dis[j] > dis[t] + w[i]) {
			dis[j] = dis[t] + w[i];
			if(!st[j]) {
				q.push(j);
				st[j] = true;
			}
		}
	}
	if(dis[n] == 0x3f3f3f3f) return -1;
	else return dis[n];
}

用SPFA查找是否负环:相较上面算法多一个全局变量 cnt[]

memset(dis, 0x3f, sizeof(dis) );
queue<int> q;
dis[1] = 1;
q.push(1);
st[1] = true;
while(q.size() ) {
	int t = q.front();
	q.pop();
	st[t] = false;
	for(int i = h[t]; i != -1; i = ne[i] ) {
		int j = e[i];
		if(dis[j] > dis[t] + w[i]) {
			dis[j] = dis[t] + w[i];
			cnt[j] = cnt[t] + 1;
			if(cnt[j] >= n) return true; // 有负环
			if(!st[j]) {
				q.push(j);
				st[j] = true;
			}
		}
	}
	return false; // 无负环
}

多源最短路
不能有负权
基于动态规划

全局变量: INF d[][] // INF 表示无穷大 1e9.
首先自己不能成环:

int n, m, h;
for(int i = 1; i <= n; ++i) {
	for(int j = 1; j <= n; ++j) {
		if(i == j) d[i][j] = 0;
		else d[i][j] = INF; 
	}
}

读入

while(h--) {
	int a,b,w;
	cin>>a>>b>>w;
	if(d[a][b] < INF /2) {
		d[a][b] = min(d[a][b], w);
	}
}

floyd算法

for(int k = 1; k <= n; ++k) {
	for(int i = 1; i <= n; ++i) {
		for(int j = 1; j <= n; ++j) {
			d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
		}
	}
}

完。
做题:luogu的最短路模板和判读负环模板。
总结:多敲敲,多想想。

你可能感兴趣的:(My学习之路,算法,图论)