图的小问题

**无向题要注意对称性

求最短路径的基本思想
按照最短路径的长度递增次序,依次求得——源点到其余各点的最短路径!

路径长度最短的最短路径的特点:
在这条路径上,必定只含有一条弧,并且这条弧的权值最小。
最短最短路径是直达的;
//第二近的城市要么是直达,要么是经过最短最短的路径转一下。

松弛操作:
{六百公里的而直达绳子,经由转放在五百公里的路径上,绳子松弛了。}

路径长度次短的最短路径的特点:
它只可能有两种情况(第二近):
或者是直接从原点到该点(只含一条弧);
或者是从原点进故宫顶点v1,在到达该顶点(有两条弧组成)。

路径长度第三短的路径的特点:
它可能有三种情况:
1、直接从原点到该点(只含一条弧);
2、从源点经过顶点v1,在到达该顶点(有两条弧组成);
3、从原点经过顶点v2,在到达该顶点。
其中1、2在上一步已经做过比较,所以——每次只需要比较2个值!

其余最短路径的特点:
或者是:直接从源点到该点(只含一条弧);
或者是:从源点金国已求得最短路径的顶点,再到达该顶点。

迪杰斯特拉算法
0)准备工作:
设置辅助数组Dist,其中每个分量Dist[k]表示:
当前所求得的从源点你到其余各顶点K的最短路径。
Dist表示从起点到其余各点的路径长度,如果没有直达则可以设为最大。
(只记录目前最短的,每求出一个最短路径,都要根据这一个点更新,每求出一个就要转一下)

1)在所有从源点出发的弧中选取一条权值最小的弧,即为第一条最短路径。
Dist[k]=Map[v0][k] V0和k之间存在弧
Dist[k]=Map[INF] V0和k之间不存在弧
其中的最小值即为最短的最短路径的长度。
**

状态转移方程?
理论表示:Dist[k]=min(Map[I][k]+Dist[i])//已经求出的新的最短路径+这个给点到k点的路径,如果松弛了,就更新一下。下面这个是实际编程,更好理解
其中,i为已经求出最短路的节点的节点编号。
假设u为刚刚求得的最短路节点,则:
实际编程:Dist[k]=min(Dist[k],Map[u][k]+Dist[u]);
举个例子,求第五短的路径时,只要比较**第从起点到第四短到第五段的距离历史求过多次最优解比较一下,就可以。因为从第二短到第五短的距离已经松弛过了,其余比第五短的也都与第五个松弛过了。
解释:因为两点之间的最短路径,也包含其它两点之间的最短路径!(动态规划的最优子结构)

思考:
求两点之间的最短路径和求一个点到其余所有点的最短路径,时间复杂度一样。
因为求出的最短路径可能是最坏的最短路径,有可能要挨个求一下,最坏情况就是求到。

//举个例子:
#include<bits/stdc++.h>
#include<stdio.h>
#define inf 0x7FFFFFFF
#define M 201
using namespace std;
int Map[M][M],Dist[M],visit[M]; 
/*struct AB{
	int a;
	int b;
	int x;
	
}str[1000];
*/
int main (){
	int m,n,i,j,a,b,dis,start,Min,next,targe;
	while(scanf("%d%d",&n,&m)==2){
		for(i=0;i<n;i++){
			visit[i]=0;
			Dist[i]=inf;
			for(j=0;j<n;j++){
				Map[i][j]=inf;
			}
		}

	while(m--){
		scanf("%d%d%d",&a,&b,&dis);
		Map[a][b]=min(Map[a][b],dis);//可能有多条路,只记录最短路 
		Map[b][a]=Map[a][b];//无向图; 
	}
      scanf("%d%d",&start,&targe);
      Dist[start]=0;
      visit[start]=1;//是否已经求出最短路径; 
      while(start!=targe){
      	Min=inf;
      	// 
      	for(i=0;i<n;i++){
      		if(Map[start][i]!=inf)//如果可达就松弛操作 
      		   Dist[i]=min(Dist[i],Map[start][i]+Dist[start]);
      	if(visit[i]&&Dist[i]<Min){
      		next=i;//最近城市 
      		Min=Dist[i];
      	 }
      	}
      	// 
      	if(Min==inf)  break;
      	start = next ;
      	visit[start] = 0; 
      }
      if(Dist[targe]==inf) puts("-1");
      else printf("%d\n",Dist[targe]) ;
       
	 }	
	
	
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值