还是拿这个题来分析
dijkstra算法思路:
是一个以出发路口为原点,不断扩充边直到将整个图联通的一个过程。 |
开始构建连通图:
一开始以出发点为原点,找到一个最邻近的点A,然后连接两点,构成一条边,这时候该点距离原点的距离就是该边权值,然后以该边A为端点,找出一个该点能联通的最短边,然后将新加入的点B更新它到原点的距离,即是原点—>A---->B的距离。这时候就叫做B和原点联通了。接着原点重复上述步骤,继续找距离原点的最小边,因为每次查找的时候都有本来就和原点联通的点,加上上一次操作新加入的点,所以可以不断扩充各点,直到最后一个点都与原点联通,这时候最小边也出来了,就是最后一个点到原点的距离,因为是每步都去最优解到最后也一定是最优的。
详见代码注释
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <vector>
#include <limits.h>
#include <cmath>
#include <algorithm>
using namespace std;
static int inf = 0x3f3f3f3f;
int vis[105]; //用来标记当前端点有没有被遍历过
vector<vector<int>> map(105,vector<int>(105,inf)); //map用来记录i到j的距离
int dis[105]; //dis用来表示某点距离出发点的距离
int n, m;
int dijkstra()
{
int pos;
memset(vis,0,sizeof(vis)); //初始化
for(int i=1;i<=n;i++) //一开始所有点离出发点的距离就是单向的
{
dis[i] = map[1][i];
}
vis[1] = 1;
dis[1] = 0;
int t = n-1; //将剩下n-1个结点放进以出发点开始的图中
while(t--)
{
int min = inf;
for(int j=1;j<=n;j++)
{
if(!vis[j]&&min>dis[j]) //找出当前构成的图距离原点的最短路
{
min = dis[j];
pos = j; //记录位置
}
}
vis[pos] = 1; //标记
for(int j=1;j<=n;j++)
{
if(!vis[j]&&min+map[pos][j]<dis[j]) //扩充该图
dis[j] = map[pos][j]+min; //和当前已经和原点连接的点相连的最短路也被联通,能到达原点,而且是该点到原点的最短路
}
}
return dis[n];
}
int main()
{
while(scanf("%d%d",&n,&m)&&(n||m))
{
for(int i=0;i<105;i++)
for(int j=0;j<105;j++)
map[i][j] = inf;
for(int i=1;i<=m;i++)
{
int x,y,time;
cin>>x>>y>>time;
map[x][y] = map[y][x] = time;
}
// cout<<"wa"<<endl;
cout<<dijkstra()<<endl;
}
return 0;
}