Dijkstra算法的各种应用(附加边权、附加点权、计算最短路径条数)

功能数组

const int MAXN = 1000;//图中最大领点个数
const int INF = 0x3fffffff;
int G[MAXN][MAXN], cost[MAXN][MAXN],weight[MAXN];//邻接矩阵存储图
//迪杰斯特拉算法需要一个访问数组来记录集合S   visited,距离数组dist,和一个前驱节点数组pre。
bool visited[MAXN];
//dist记录最短距离,pre记录前驱节点,c记录最小边花费,wg记录最大点累积,num记录最短路径数目
int dist[MAXN], pre[MAXN],c[MAXN],wg[MAXN],num[MAXN];
vector<int> G1[MAXN];//邻接表存储图
int n, m, u, v, w;//节点数,边数,边u->v的权值w

//最短距离加最短路径(只求最短距离和最短路径)核心部分的注释就只出现在这个程序中啦,下面的代码中注释就不会有这么多了,因为大部分都差不多。

void Dijkstra(int start) {
	//迪杰斯特拉算法第一步:变量初始化-------------
	//1、如果多次调用迪杰斯特拉算法这一步是需要的。若只调用一次的话可以不需要这一步,因为全局变量的visited默认值就是全false
	fill(visited, visited + n, false);
	fill(dist, dist + n, INF);
	for (int i = 0; i < n; i++) pre[i] = i;
	dist[start] = 0;
	//visited[start] = true;不需要这一句因为在接下来的一轮循环中,start节点就是dist[]中最小的一个节点。	
	//-----------------------------------初始化步骤完成--------------------------------------
	//2、寻找n次dist[]中的最小值,即最小距离,  然后再对选中的最小节点进行dist[]优化。也就是迪杰斯特拉算法中i->v->j 桥接优化
	for (int i = 0; i < n; i++) {
		int minw = INF, index = -1;//minw记录最小权重,index记录最小权重的节点下标。
		//第一个循环找出dist[]中最小的值,也就是最短边
		for (int j = 0; j < n; j++) {
			if (visited[j] == false && minw > dist[j]) {
				minw = dist[j];
				index = j;
			}
		}
		if (index == -1) return;//若没有小于INF的dist[index]那么就说明剩下的顶点和起点S不联通。
		visited[index] = true;
		//第二个循环进行dist[]优化,
		for (int v = 0; v < n; v++) {
			//若以index为中介点可以使得dist[]更优。
			if (visited[v] == false && dist[v] > dist[index] + G[index][v]) {
				dist[v] = dist[index] + G[index][v];
				pre[v] = index;//记录v的前驱节点
			}
		}
	}
}

//最短距离加最短路径(附加边权值)同等距离下边权值越小越好

void Dijkstra_Add_EdgeCost(int start) {
	fill(visited, visited + n, false);
	fill(dist, dist + n, INF);
	fill(c, c + MAXN, INF);
	for (int i = 0; i < n; i++) pre[i] = i;
	dist[start] = 0; c[start] = 0;
	for (int i = 0; i < n; i++) {
		int minw = INF, index = -1;
		for (int j = 0; j < n; j++) {
			if (visited[j] == false && minw > dist[j]) {
				minw = dist[j];
				index = j;
			}
		}
		if (index == -1) return;
		visited[index] = true;
		for (int v = 0; v < n; v++) {
			if (visited[v] == false) {
				if (dist[v] > dist[index] + G[index][v]) {
					dist[v] = dist[index] + G[index][v];
					c[v] = c[index] + cost[index][v];
					pre[v] = index;
				}
				//若距离相同则优先选择路径花费最小的路径
				else if (dist[v] == dist[index] + G[index][v] && c[v] > c[index] + cost[index][v]) {
					c[v] = c[index] + cost[index][v];
					pre[v] = index;
				}
			}
		}
	}
}

//最短距离加最短路径(附加点权值)同等距离下点权值越大越好

void Dijkstra_Add_VertexCost(int start) {
	fill(visited, visited + n, false);
	fill(dist, dist + n, INF);
	fill(wg, wg + MAXN, 0);
	for (int i = 0; i < n; i++) pre[i] = i;
	dist[start] = 0; c[start] = 0;
	for (int i = 0; i < n; i++) {
		int minw = INF, index = -1;
		for (int j = 0; j < n; j++) {
			if (visited[j] == false && minw > dist[j]) {
				minw = dist[j];
				index = j;
			}
		}
		if (index == -1) return;
		visited[index] = true;
		for (int v = 0; v < n; v++) {
			if (visited[v] == false) {
				if (dist[v] > dist[index] + G[index][v]) {
					dist[v] = dist[index] + G[index][v];
					wg[v] = wg[index] + weight[v];//start到v中间加上了一个index点
					pre[v] = index;
				}
				//若距离相同则优先选择路径花费最小的路径
				else if (dist[v] == dist[index] + G[index][v] && wg[v] < wg[index] + weight[v]) {
					wg[v] = wg[index] + weight[v];
					pre[v] = index;
				}
			}
		}
	}
}

//记录最短路径的条数

void Dijkstra_Add_PathCnt(int start) {
	fill(visited, visited + n, false);
	fill(dist, dist + n, INF);
	fill(num, num + n, 0);
	num[start] = 1;
	for (int i = 0; i < n; i++) pre[i] = i;
	dist[start] = 0; c[start] = 0;
	for (int i = 0; i < n; i++) {
		int minw = INF, index = -1;
		for (int j = 0; j < n; j++) {
			if (visited[j] == false && minw > dist[j]) {
				minw = dist[j];
				index = j;
			}
		}
		if (index == -1) return;
		visited[index] = true;
		for (int v = 0; v < n; v++) {
			if (visited[v] == false) {
				if (dist[v] > dist[index] + G[index][v]) {
					dist[v] = dist[index] + G[index][v];
					num[v] = num[index];
					pre[v] = index;
				}
				//若距离相同则优先选择路径花费最小的路径
				else if (dist[v] == dist[index] + G[index][v]) {
					num[v] += num[index];//假设有p条路到index那么就至少有p条路到v
				}
			}
		}
	}
}

查找路径

void findPath(int start,int v) {
	if (start == v) {
		cout << v << " ";
		return;
	}
	findPath(start, pre[v]);
	cout << v << " ";
}

完整测试代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1000;//图中最大领点个数
const int INF = 0x3fffffff;
int G[MAXN][MAXN], cost[MAXN][MAXN],weight[MAXN];//邻接矩阵存储图
//迪杰斯特拉算法需要一个访问数组来记录集合S   visited,距离数组dist,和一个前驱节点数组pre。
bool visited[MAXN];
int dist[MAXN], pre[MAXN],c[MAXN],wg[MAXN],num[MAXN];
vector<int> G1[MAXN];//邻接表存储图
int n, m, u, v, w;//节点数,边数,边u->v的权值w
//最短距离加最短路径(只求最短距离和最短路径)
void Dijkstra(int start) {
	//迪杰斯特拉算法第一步:变量初始化-------------
	//1、如果多次调用迪杰斯特拉算法这一步是需要的。若只调用一次的话可以不需要这一步,因为全局变量的visited默认值就是全false
	fill(visited, visited + n, false);
	fill(dist, dist + n, INF);
	for (int i = 0; i < n; i++) pre[i] = i;
	dist[start] = 0;
	//visited[start] = true;不需要这一句因为在接下来的一轮循环中,start节点就是dist[]中最小的一个节点。	
	//-----------------------------------初始化步骤完成--------------------------------------
	//2、寻找n次dist[]中的最小值,即最小距离,  然后再对选中的最小节点进行dist[]优化。也就是迪杰斯特拉算法中i->v->j 桥接优化
	for (int i = 0; i < n; i++) {
		int minw = INF, index = -1;//minw记录最小权重,index记录最小权重的节点下标。
		//第一个循环找出dist[]中最小的值,也就是最短边
		for (int j = 0; j < n; j++) {
			if (visited[j] == false && minw > dist[j]) {
				minw = dist[j];
				index = j;
			}
		}
		if (index == -1) return;//若没有小于INF的dist[index]那么就说明剩下的顶点和起点S不联通。
		visited[index] = true;
		//第二个循环进行dist[]优化,
		for (int v = 0; v < n; v++) {
			//若以index为中介点可以使得dist[]更优。
			if (visited[v] == false && dist[v] > dist[index] + G[index][v]) {
				dist[v] = dist[index] + G[index][v];
				pre[v] = index;//记录v的前驱节点
			}
		}
	}
}
//最短距离加最短路径(附加边权值)同等距离下边权值越小约好
void Dijkstra_Add_EdgeCost(int start) {
	fill(visited, visited + n, false);
	fill(dist, dist + n, INF);
	fill(c, c + MAXN, INF);
	for (int i = 0; i < n; i++) pre[i] = i;
	dist[start] = 0; c[start] = 0;
	for (int i = 0; i < n; i++) {
		int minw = INF, index = -1;
		for (int j = 0; j < n; j++) {
			if (visited[j] == false && minw > dist[j]) {
				minw = dist[j];
				index = j;
			}
		}
		if (index == -1) return;
		visited[index] = true;
		for (int v = 0; v < n; v++) {
			if (visited[v] == false) {
				if (dist[v] > dist[index] + G[index][v]) {
					dist[v] = dist[index] + G[index][v];
					c[v] = c[index] + cost[index][v];
					pre[v] = index;
				}
				//若距离相同则优先选择路径花费最小的路径
				else if (dist[v] == dist[index] + G[index][v] && c[v] > c[index] + cost[index][v]) {
					c[v] = c[index] + cost[index][v];
					pre[v] = index;
				}
			}
		}
	}
}
//最短距离加最短路径(附加点权值)同等距离下点权值越大越好
void Dijkstra_Add_VertexCost(int start) {
	fill(visited, visited + n, false);
	fill(dist, dist + n, INF);
	fill(wg, wg + MAXN, 0);
	for (int i = 0; i < n; i++) pre[i] = i;
	dist[start] = 0; c[start] = 0;
	for (int i = 0; i < n; i++) {
		int minw = INF, index = -1;
		for (int j = 0; j < n; j++) {
			if (visited[j] == false && minw > dist[j]) {
				minw = dist[j];
				index = j;
			}
		}
		if (index == -1) return;
		visited[index] = true;
		for (int v = 0; v < n; v++) {
			if (visited[v] == false) {
				if (dist[v] > dist[index] + G[index][v]) {
					dist[v] = dist[index] + G[index][v];
					wg[v] = wg[index] + weight[v];//start到v中间加上了一个index点
					pre[v] = index;
				}
				//若距离相同则优先选择路径花费最小的路径
				else if (dist[v] == dist[index] + G[index][v] && wg[v] < wg[index] + weight[v]) {
					wg[v] = wg[index] + weight[v];
					pre[v] = index;
				}
			}
		}
	}
}
//记录最短路径的条数
void Dijkstra_Add_PathCnt(int start) {
	fill(visited, visited + n, false);
	fill(dist, dist + n, INF);
	fill(num, num + n, 0);
	num[start] = 1;
	for (int i = 0; i < n; i++) pre[i] = i;
	dist[start] = 0; c[start] = 0;
	for (int i = 0; i < n; i++) {
		int minw = INF, index = -1;
		for (int j = 0; j < n; j++) {
			if (visited[j] == false && minw > dist[j]) {
				minw = dist[j];
				index = j;
			}
		}
		if (index == -1) return;
		visited[index] = true;
		for (int v = 0; v < n; v++) {
			if (visited[v] == false) {
				if (dist[v] > dist[index] + G[index][v]) {
					dist[v] = dist[index] + G[index][v];
					num[v] = num[index];
					pre[v] = index;
				}
				//若距离相同则优先选择路径花费最小的路径
				else if (dist[v] == dist[index] + G[index][v]) {
					num[v] += num[index];//假设有p条路到index那么就至少有p条路到v
				}
			}
		}
	}
}
void findPath(int start,int v) {
	if (start == v) {
		cout << v << " ";
		return;
	}
	findPath(start, pre[v]);
	cout << v << " ";
}
void input() {
	fill(G[0], G[0] + MAXN * MAXN, INF);
	scanf("%d %d", &n, &m);
	for (int i = 0; i < m; i++) {
		scanf("%d %d %d", &u, &v, &w);
		G[u][v] = w;
	}
	for (int i = 0; i < m; i++) {
		scanf("%d %d %d", &u, &v, &w);
		cost[u][v] = w;
	}
	for (int i = 0; i < n; i++) {
		scanf("%d", &weight[i]);
	}
}
int main() {
	freopen("Text.txt", "r", stdin);
	input();
	Dijkstra_Add_PathCnt(0);
	for (int i = 0; i < n; i++) cout << dist[i] << " ";
	cout << endl;
	for (int i = 0; i < n; i++) cout << num[i] << " ";
	cout << endl;
	findPath(0, 3);
}

猜你喜欢

转载自blog.csdn.net/qq_39072627/article/details/107441432