一场说走就走的旅行-最短路径

Dijkstra算法:
是解决单源最短路径问题的贪心算法,它先求出长度最短路径的一条路径,再参照该最短路劲求出长度次短的一条路径直到求出从源点
到其他各个顶点的最短路径。
Dijkstra算法得基本思想是首先假定源点为u,顶点集合V被划分为两部分:集合S和V-S。初始时S中仅含有源点u,其中S中的顶点到源点的最短路径已经确定。集合V-S中所含有的顶点到源点的最短路径的长度待定,并且用数组dist[]记录当前每个顶点所对应的最短特殊路径长度。

dijkstra算法采用的贪心策略是选择特殊路径长度最短路径,将其连接到V-S中的顶点并将该节点加入到dist[]数组当中,一旦dist[]数组中包含了所有顶点dist[]就是从源点到所有其他顶点之间的最短路径。
数据结构:
(1)设置地图的带权邻接矩阵map[][],即如果从源点u到顶点i有边,就令map[][]等于源点到各个结点的权值
(2)初始化。令集合S={u},对于集合V-S中顶点x,初始化dist [i] =map [u] [ i ]
(3)找最小。在集合V-S中依照贪心策略来寻找使得dist[j]具有最小值的顶点t,
(4)加入集合S中
(5)判结束。如果集合V-S为空,算法结束,否则转6
(6)在(3)中判断找那个已经找到了源点到t的最短路径,那么对集合V-S中所有与顶点t相邻的顶点j,都可以借助t走捷径。如果dist[j]>dist[t]+map[t][j],则dis[j]=dis[t]+map[t][j]记录顶点j的前驱为t,有p[i]=t;用于存储path(路径)。

#include<iostream>
#include<algorithm>
#include<stack>
#define INF 1000
using namespace std;

const int maxn=1000+5;
int dist[maxn];//用于存储源点到各个结点的距离
int map[maxn][maxn];//用于存储各个结点之间的距离
int n,m,k;//输入
int S[maxn];//用于存储结点集合
int p[maxn];//用于存储前驱
void Dijkstra(int u)
{
	for(int j=1;j<=n;j++)
	{
		dist[j]=map[u][j];//将与u结点连接的结点存入dist[];		
		S[j]=0;//默认结点都没有被访问
		if(dist[j]==INF)//如果值为无穷大则可判定为该节点与源节点没有连接
			p[j]=-1;//标记为-1
		else	
			p[j]=u;//标记为u
	}//预处理
	dist[u]=0;
	S[u]=1;//将源结点标记为已访问
	for(int i=1;i<=n;i++)
	{
		int temp=INF;
		int t=u;
		for(int j=1;j<=n;j++)
		{
			if(temp>dist[j]&&!S[j]==1)
			{
				temp=dist[j];
				t=j;
			}
		}//找与源结点距离最近的一个结点
			if(t==u)
				return ;
			S[t]=1;//标记为已访问
			for(int k=1;k<=n;k++)
			{
				if(!S[k]==1&&dist[t]+map[t][k]<dist[k]&&map[t][k]<INF)
				{ 	
					dist[k]=dist[t]+map[t][k];
					p[k]=t;
				}
			}//将该最小结点来判断是否可以让剩下的结点的值更小
		}			
		
}
int main()
{
	cin>>n>>m;
	int a,b,c;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			map[i][j]=INF;
	for(int i=1;i<=m;i++)
	{
		cin>>a>>b>>c;
		map[a][b]=min(map[a][b],c);
	}
	cin>>k;
	Dijkstra(k);
	stack<int>s;
	for(int i=1;i<=n;i++)
	{
		int t=p[i];
		while(t!=-1)
		{
			s.push(t);
			t=p[t];
		}
		while(!s.empty())
		{
			cout<<s.top()<<"->";
			s.pop();
		}
		cout<<i<<" "<<dist[i]<<endl;
	}
	
}

代码优化:
才用优先队列的方式:因为每次选择一个新的结点以后我们就需要更新以下的结点,进行重新排序,所以我们
不妨把每次访问后的结点直接pop出去,再利用queue队列的排序的功能再从队列的顶部取得一个元素,查看之后结点是否可以
继续更新,省去的每次循环都要找最小的步骤。

#include<iostream>
#include<queue>
#include<algorithm>
#include<cstdlib>
#include<cstring>
using namespace std;

const int maxn=1000;
int flag[maxn];
const int INF=1e7;
int map[maxn][maxn];
int dist[maxn];
int n,m;
struct Node{
	int u;
	int step;
	Node()
	{};
	Node(int a,int b){
		u=a;
		step=b;
	}
	operator < (const Node &a)const{
		return step>a.step;
	}
};
void DijKstra(int st)
{
	priority_queue<Node> Q;
	Q.push(Node(st,0));
	memset(flag,0,sizeof(flag));
	for(int i=1;i<=n;i++)
		dist[i]=INF;//这里要初始化为最大值,需要将源点入队。
	dist[st]=0;
	while(!Q.empty())
	{
		Node it=Q.top();
		Q.pop();
		int t=it.u;
		if(flag[t])//该节点已经访问过了
			continue;
		flag[t]=1;
		for(int i=1;i<=n;i++)
		{
			if(!flag[i]&&map[t][i]<INF)
			{
				if(dist[t]+map[t][i]<dist[i])
				{
					dist[i]=dist[t]+map[t][i];
					Q.push(Node(i,dist[i]));
				}
			}
		}//for
	}//while
	}
	int main()
	{
		int k;
		cin>>n>>m;
		for(int i=1;i<=n;i++)		
			for(int j=1;j<=n;j++)
				map[i][j]=INF;
		while(m--)
		{
			int a,b,c;
			cin>>a>>b>>c;
			map[a][b]=min(map[a][b],c);
		}
		cin>>k;
		DijKstra(k);
		for(int i=1;i<=n;i++)
		{
			cout<<k<<"-->"<<i<<":";
			if(dist[i]==INF)
				cout<<"无路可走"<<endl;
			else
				cout<<dist[i]<<endl;
		}
}//main
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值