一、问题
带权有向图G(E,V), 找出从给定源顶点s到其它顶点v的权最小路径。
“最短路径” = 最小权
二、问题求解:
求1到5的最短路径值?
三、执行过程:
如果大家对这个问题的要求还不是很明白的话那么我再带着大家走一遍:
第一次:从1-->2:10 此时从1-->3没有路径所有是无穷大 1-->4:30 1-->5:100那么我们发现这一组组最小的是10也就是2这一点,所以我们再把2这一点加到集合里面来,那么2这一点就可以当作一个桥来用,
第二次:此时我们再从1-->3就可以通过1-->2-->3: 60,其他的1-->4:30
1-->5:100 可以发现此时最小的应该是4,所以我们再把4这一点加入到这个集合里面来,如此重复的去做这些事情,到最后可以发现1-->5的最短路径应该是60(1-->4-->3-->5)
四、Dijkstra伪代码:
- int dijkstra(int s,int t) {
- 初始化S={空集}
- d[s] = 0; 其余d值为正无穷大
- while (NOT t in S)
- {
- 取出不在S中的最小的d[i];
- for (所有不在S中且与i相邻的点j)
- if (d[j] > d[i] + cost[i][j]) d[j] = d[i] + cost[i][j]; ( “松弛”操作” )
- S = S + {i}; //把i点添加到集合S里
- }
- return d[t];
- }
为何松弛操作:
也就是说如果1-->3这点的值为dist[3]>dist[2]+map[2][3]
那么dist[3]=dits[2]+map[2][3]
五、代码实现:
- #include <iostream>
- using namespace std;
- #define MAX 9999999
- #define LEN 210
- int map[LEN][LEN]; //某点到某点两点间的的距离
- int dist[LEN]; //记录当前点到源点的最短路径长度
- int mark[LEN]; //加入进来的点的集合
- //初始化map为正无穷大
- void init(){
- int i,j;
- for(i=0;i<LEN;i++){
- for(j=0;j<LEN;j++){
- map[i][j]=MAX;
- }
- }
- }
- //n:多少条路 start:起始点
- void myDijstra(int n,int start){
- int i,j,min,k;
- for(i=1;i<=n;i++){
- mark[i]=0;//没有点加入
- dist[i]=map[start][i];//初始
- }
- mark[start]=1;//把起始点加进来
- dist[start]=0;
- for(i=1;i<=n;i++){
- min=MAX;
- for(j=1;j<=n;j++){
- if(!mark[j] && dist[j]<min){ //取出不在mark里的最小的dist[i]
- min=dist[j];
- k=j;//标记
- }
- }
- if(min==MAX)
- break;
- mark[k]=1;//把K加进来
- //做松弛操作
- for(j=1;j<=n;j++){
- if(!mark[j] && dist[j]>dist[k]+map[k][j]){
- dist[j]=dist[k]+map[k][j];
- }
- }
- }
- }
- int main(){
- int i,j,n,line;
- int a,b,d;
- cin>>n>>line; //输入点和边
- init();
- for(i=0;i<line;i++){
- cin>>a>>b>>d; //输入各边的权值
- if(map[a][b]>d){
- map[a][b]=map[b][a]=d;
- }
- }
- myDijstra(n,1);//调用方法
- //输出1到5的最短路径
- cout<<dist[5]<<endl;
- return 0;
- }
六、测试数据:
5 7
1 2 10
1 4 30
1 5 100
2 3 50
3 5 10
4 3 20
4 5 60
结果:
-
顶
- 6
-
踩
- 0