#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int inf=1<<29; const int N=1001; int n,m,d[N],w[N][N]; bool vis[N]; void dij() { for(int i=1; i<=n; i++)//把从起点到其余每个点的距离设为无穷大,方便此后的松弛操作 d[i]=inf; d[1]=0;//以1为起点 for(int i=0; i<n; i++)//确保不会遗漏松弛,循环n次(因为每次只取当前与原点距离最小值,每个值都要遍历一遍) { int now=inf; int x; for(int j=1; j<=n; j++)//从前到后,把起点到每个点的距离都拿出来比一遍(每一次循环,距离都会有更新) { if(!vis[j]&&now>d[j])//vis避免前面已经比过了的最小值的点重复比较 { //一直找出此时离起点最近的点,以此点为基础,向下找其他点到该点的距离, now=d[j]; x=j; } } // printf("x=%d ",x); vis[x]=1; for(int j=1; j<=n; j++)//从x点到其他所有点,全部遍历,进行距离的更新(松弛)操作, { //!vis[j]避免与前面的最小点重复更新 if(!vis[j]&&d[j]>d[x]+w[x][j])//如果(这一点到x的距离加x到起点的距离)小于之前存的此点到起点的距离 { d[j]=d[x]+w[x][j];//则更新成新的距离 //printf("d[%d]=%d ",j,d[j]); } } } } int main() { while(~scanf("%d%d",&n,&m))//点数,边数 { memset(vis,0,sizeof(vis)); for(int i=1; i<=n; i++) { for(int j=1; j<=n; j++) { w[i][j]=inf;//点i到点j的距离全部初始化为无穷大 } } while(m--) { int u,v,c; scanf("%d%d%d",&u,&v,&c);//起点,终点,权值 if(c<w[u][v]) w[u][v]=w[v][u]=c;//无向图付出权值 } dij(); for(int i=2; i<=n; i++)//全部输出每个点到起点的最小值 { printf("%d %d ",i,d[i]); } } return 0; } /* input 7 12 1 2 24 1 3 8 1 4 15 2 5 6 3 5 7 3 6 3 4 7 4 5 7 9 6 5 2 6 7 3 6 4 5 7 2 3 output 2 17 3 8 4 15 5 13 6 11 7 14*/
局限性:当A到A的距离为0 代码切入到子函数最下方,A到B的距离更新为3,A到C的距离更新为2,再循环找出C点,标记C点已经不能在更新,这是有向图,C不能再向下更新,回去再循环,找出B点,,当B点准备向下更新时,因为之前C点已经被标记,这里会直接跳过C点,不能对其更新,算出的结果是2,但实际上是3-2=1,所以这个算法不能算带有负权值的图