利用分支界限法求解Dijikstra算法

前记

对于迪杰斯特拉算法的贪心解法请移步:最短路径算法(上)——迪杰斯特拉(Dijikstra)算法

算法流程

1 初始化最小堆q,距离数组dist全为无穷大,collected数组为全0,path数组全为-1,dist[i]代表顶点i到源顶点的最短距离,最小堆按照dist的大小进行排序,源顶点为s,dist[s]=0。源顶点s加入最小堆。Collected[i]代表顶点i是否加入最小堆,0代表未收录,1代表收录。path[i]代表顶点i最短路径上的中间顶点,其中-1代表源顶点。
2 从最小堆中弹出堆顶元素start,之后遍历(bfs)相邻结点i,若start和i之间的权重G[start][i]+dist[start]<dist[i],那么dist[i]=G[start][i]+dist[start]。并且将i加入最小堆。
3 最小堆不为空时,循环执行步骤2


C++代码

#include <iostream>
#include <cstring>
#include <stack>
#include <queue> 
#include <vector> 
using namespace std;

const int MAX = 65535;
int G[1001][1001];
int dist[1001] = {0};
int path[1001] = {0};
int visited[1001] = {0};
int Nv,Ne;
int start;

struct cmp{
	bool operator()(int &a,int &b){
		return dist[a]>dist[b];
	}
};

void Create_Graph()
{
	//初始化距离数组为正无穷 
	for(int i = 0 ; i < 1001 ; i++){
		dist[i] = MAX;
	}
	//初始化路径数组为-1 
	memset(path,-1,sizeof(path[0])*(1001));
	//初始化访问数组为-1 
	memset(visited,0,sizeof(visited[0])*(1001));
	//memset(this->collected,0,sizeof(this->collected[0])*(nv+1));
	for(int i = 0 ; i < 1001 ; i++){
		for(int j = 0 ; j < 1001 ; j++){
			G[i][j] = MAX;	
		}
	}
	//初始化图
	cout<<"请输入顶点数与边数:"<<endl; 
	cin>>Nv>>Ne;
	cout<<"请输入边与权重:"<<endl;
	for(int i = 0 ; i < Ne ; i++){
		int v1,v2,weight;
		cin>>v1>>v2>>weight;
		G[v1][v2] = G[v2][v1] = weight;
	}	
}

//迪杰斯特拉算法 
bool Dijikstra(int vertex)
{
	priority_queue<int,vector<int>,cmp> q;
	//源顶点加入最小堆 
	q.push(vertex);
	//初始化源顶点的dist为0 
	dist[vertex] = 0;
	visited[vertex] = 1; 
	//最小堆不为空,一直循环 
	while(!q.empty()){
		//从最小堆中弹出最小元素 
		int start = q.top();
		q.pop();
		for(int i = 1 ; i < Nv+1 ; i++){
			//负值圈问题 
			if(G[start][i] < 0){
				return false;
			}
			// bfs遍历领接结点 
			if (G[start][i] < MAX){
				if(visited[i] == 0){
					// i到start的最小距离大于dist[start]+G[start][i]
					if(dist[i] > dist[start] + G[start][i]){
						dist[i] = dist[start] + G[start][i];
						q.push(i);
						path[i] = start;
					}	
				}	
			}
		}
	}
	return true;
}

//打印start到end的最短路径 
void Print(int start ,int end)
{
	stack<int> stack;
	stack.push(end);
	cout<<start<<"到"<<end<<"的最短路径为:";
	int j = end;
	while(path[j] != -1){//路径上的元素一次入栈 
		j = path[j];
		stack.push(j);	
	}
	//打印路径 
	cout<<stack.top();
	stack.pop(); 
	while(!stack.empty()){
	cout<<" -> "<<stack.top();
	stack.pop();
	}
	cout<<"\n"<<"最短路径长度为:"<<dist[end]<<endl;
}

void Print_Dijikstra(int vertex)
{
	for(int i = 1 ; i < Nv+1 ; i++){
		if(i == vertex){
			continue;
		} 
		Print(vertex,i); 
	}
}


int main() 
{
	Create_Graph();
	cout<<"请输入一个起始点:"<<endl;
	int vertex;
	cin>>vertex;
	if(Dijikstra(vertex)){
		Print_Dijikstra(vertex); 	
	}
	
	return 0;
}

例子

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

daipuweiai

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值