带权图最短路径问题

本文总结了小学期学到的算法,包括单源最短路问题的Bellman-Ford、SPFA和Dijkstra算法,以及解决任意两点间最短路的Floyd-Warshall算法。Dijkstra算法利用优先队列实现O(|E|×log|V|)的时间复杂度,Floyd-Warshall通过动态规划达到O(|V|3)的时间复杂度。
摘要由CSDN通过智能技术生成

小学期学的算法和做OJ题的各种经验总结

一、单源最短路问题

  1. Bellman-Ford算法:O(|V|×|E|)
    (浪费时间,遍历每一条边的时候不知道当前边的de.from是不是正确的最短距离; 而且对于每个点都要遍历一次该点的相连边)
    从起点到第i个点的最短距离di = min{dj + wij | j与i相邻} (所有(到点i相邻的点(j)的最小距离 + 这两个点的距离)中的最小值)实现方法:存边的to, distance,初始化最短路径数组d[]为INF。按点遍历,每个点遍历一次所有的相连边。 di 就是de.to
//从起点到第i个点的最短距离di = min{d(j) + w(i,j) | j与i相邻}
// (所有(到点i相邻的点(j)的最小距离 + 这两个点的距离)中的最小值)
//实现方法:存边的to, distance,初始化最短路径数组d[]为INF,,d[起点]=0。
//按点遍历,每个点遍历一次所有的相连边。 d(i) 就是mint(d[e.to] + e.distance)
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <vector>
#include <climits>

using namespace std;

struct edge
{
   
	int to, cost;
	edge(int _to, int _d) :to(_to), cost(_d) {
   };
};

const int MAXV = 100;//点数
vector<edge> g[MAXV];//第i个点的相连边
vector<edge>::iterator it;
int d[MAXV];
const int INF = INT_MAX;

//不判断负环的Bellman,不用
void BellmanFord(int v) {
   
	//s 起点
	bool update;
	do {
   
		update = false;
		for (int j = 1;j <= v;j++) {
   
			for (it = g[j].begin(); it != g[j].end(); it++) {
   
				edge e = *it;
				int i = e.to;
				if (d[j] != INF && d[j] + e.cost < d[i]) {
   
					d[i] = d[j] + e.cost;
					update = true;
				}
			}
		}
		
	} while (update);

}

//存在负圈则会经过同一个点两次
//没有负圈的话遍历完v-1个点d[v]就应该有了,如果走到v再走点v到点v的邻边比直接到v的邻边还短(会更新d[邻边])
//说明存在负环

//存在负圈返回true
bool negative_BellmanFord(int v, int start) {
   
	//如果d[start]为负则存在负环
	bool update;
	do {
   
		update = false;
		for (int j = 1; j <= v; j++) {
   
			for (it = g[j].begin(); it != g[j].end(); it++) {
   
				edge e = *it;
				int i = e.to;
				if (d[j] != INF && d[j] + e.cost < d[i]) {
   
					d[i] = d[j] + e.cost;
					update = true;
				}
			}
		}
		if (d[start] < 0) return true;//存在负环
	} while (update);
	return false;
}

void addEdge(const int &f, const int &t, const int &cost) {
   
	g[f].push_back(edge(t, cost));
}

int main() {
   
	输入数据
	//无负环
	//int v = 6;
	//
	//g[1].push_back(edge(2, 5));	g[1].push_back(edge(3, 1));
	//g[2].push_back(edge(1, 5));	g[2].push_back(edge(3, 2));	g[2].push_back(edge(4, 1));
	//g[3].push_back(edge(1, 1));	g[3].push_back(edge(2, 2));	g[3].push_back(edge(4, 4));	g[3].push_back(edge(5, 8));
	//g[4].push_back(edge(2, 1));	g[4].push_back(edge(3, 4));	g[4].push_back(edge(5, 3));	g[4].push_back(edge(6, 6));
	//g[5].push_back(edge(3, 8));	g[5].push_back(edge(4, 3));
	//g[6].push_back(edge(4, 6));
	
	//有负环
	int v = 4;
	addEdge(1, 2, 1); //addEdge(1, 4, -3);
	addEdge(2, 3
下面是使用Dijkstra算法求解无向带权最短路径的C语言代码实现,其中采用了邻接矩阵来表示: ```c #include <stdio.h> #include <limits.h> #define V 5 // 的顶点数 // 找到距离数组中最小距离对应的顶点 int min_distance(int dist[], int visited[]) { int min = INT_MAX, min_index; for (int v = 0; v < V; v++) { if (!visited[v] && dist[v] < min) { min = dist[v]; min_index = v; } } return min_index; } // 使用Dijkstra算法求解最短路径 void dijkstra(int graph[V][V], int start) { int dist[V], visited[V]; // 初始化距离数组和访问数组 for (int v = 0; v < V; v++) { dist[v] = INT_MAX; visited[v] = 0; } dist[start] = 0; // 遍历所有顶点 for (int count = 0; count < V - 1; count++) { // 找到距离数组中最小距离对应的顶点 int u = min_distance(dist, visited); // 将该顶点标记为已访问 visited[u] = 1; // 更新所有未访问的相邻顶点的距离 for (int v = 0; v < V; v++) { if (!visited[v] && graph[u][v] && dist[u] != INT_MAX && dist[u] + graph[u][v] < dist[v]) { dist[v] = dist[u] + graph[u][v]; } } } // 输出最短距离 printf("最短距离:\n"); for (int i = 0; i < V; i++) { printf("%d\t", dist[i]); } printf("\n"); } // 测试代码 int main() { // 定义的邻接矩阵 int graph[V][V] = { {0, 2, 0, 1, 0}, {2, 0, 3, 2, 0}, {0, 3, 0, 1, 4}, {1, 2, 1, 0, 3}, {0, 0, 4, 3, 0} }; // 求解最短路径 dijkstra(graph, 0); return 0; } ``` 在上述代码中,我们首先定义了的邻接矩阵,然后实现了`min_distance()`函数来找到距离数组中最小距离对应的顶点。接着,我们使用Dijkstra算法求解最短路径,首先初始化距离数组和访问数组,将起始顶点的距离设为0。然后,我们遍历所有顶点,每次找到距离数组中最小距离对应的顶点,并将该顶点标记为已访问。接着,我们更新所有未访问的相邻顶点的距离。最后,输出最短距离。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值