(不能有负权边)
!长度步数显示法!
集合1:已最短点集合
集合2:未最短点到源点距离集合
第一开始把和源点连接的点的距离排序起来
那么2里最小的一定是源点到这个点的最短路径
因为从源点如果想到这个点有一条其它更短路径
那么这个路径只能是1集合到这个点,如果从2集合就已经更长了
而集合1里到这个点的路径已经被松弛过了是最短的
接下来再往下松弛(用当前节点更新别的节点的距离)
那么2里最小的,一定是源点到这个点的最短路径
因为从源点出发,如果不是经历的当前同样路径,想更短
那么这个路径只能是1集合到这个点,如果2集合就已经更长了
而集合1里到这个点的路径已经被松弛过了是最短的
1:dij本质上其实是贪心
2:不可能用比当前最短的路径长的路径去更新别的路径
3:每次都会找到一个最短的路径
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
inline int read()
{
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
int main()
{
int N,M,A,B,C,temp;
int dis[105],mp[105][105];
bool vis[105];
while((N=read())&&(M=read()))
{
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
mp[i][j]=10000000;
for(int i=1;i<=N;i++) dis[i]=10000000;
for(int i=1;i<=N;i++) vis[i]=0;
dis[0]=10000000; //!!!!!!!!!!!
dis[1]=0;
for(int i=1;i<=M;i++)
{
A=read(); B=read(); C=read();
if(mp[A][B]>C) mp[A][B]=C;
if(mp[B][A]>C) mp[B][A]=C;
}
for(int i=1;i<=N;i++)
{
temp=0;
for(int i=1;i<=N;i++)
{
if(!vis[i]&&dis[i]<dis[temp]) temp=i;
}
vis[temp]=1;
if(temp==N) break;
for(int i=1;i<=N;i++)
{
if(dis[temp]+mp[temp][i]<dis[i]) dis[i]=dis[temp]+mp[temp][i];
}
}
printf("%d\n",dis[N]);
}
return 0;
}
来源:CSDN
作者:莱因哈特别能撞
链接:https://blog.csdn.net/qq_40118223/article/details/104429280