Dijkstra算法

一.最短路径的最优子结构性质

   该性质描述为:如果P(i,j)={Vi....Vk..Vs...Vj}是从顶点i到j的最短路径,k和s是这条路径上的一个中间顶点,那么P(k,s)必定是从k到s的最短路径。即如果存在一条从i到j的最短路径(Vi.....Vk,Vj),那么(Vi...Vk)也必定是从i到k的最短路径。

二.定义

Dijkstra(迪杰斯特拉)算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。

三.算法思想

    每次新扩展一个距离最短的点,更新与其相邻的点的距离。当所有边权都为正时,由于不会存在一个距离更短的没扩展过的点,所以这个点的距离永远不会再被改变,因而保证了算法的正确性。不过根据这个原理,用Dijkstra求最短路的图不能有负权边,因为扩展到负权边的时候会产生更短的距离,有可能就破坏了已经更新的点距离不会改变的性质。

四.算法实现

初始时,源点s的路径长度值被赋为0(d[s]=0), 同时把所有其他顶点的路径长度设为无穷大,如果存在一条从u到v的边,那么从s到u的最短路径可以通过将边(u,v)添加到尾部来拓展一条从s到v的路径。这条路径的长度是d[u]+w(u,v)。如果这个值比目前已知的d[v]的值要小,我们可以用新值来替代当前d[v]中的值。

算法结束时,d[v]中储存的便是从s到v的最短路径,或者如果路径不存在的话是无穷大。

时间复杂度   O(n²)

一道水题

 

最短路

 

Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 83466    Accepted Submission(s): 36120

 

 

Problem Description

在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店到赛场的路线,你可以帮助他们吗?
 

 

 

Input

输入包括多组数据。每组数据第一行是两个整数N、M(N<=100,M<=10000),N表示成都的大街上有几个路口,标号为1的路口是商店所在地,标号为N的路口是赛场所在地,M则表示在成都有几条路。N=M=0表示输入结束。接下来M行,每行包括3个整数A,B,C(1<=A,B<=N,1<=C<=1000),表示在路口A与路口B之间有一条路,我们的工作人员需要C分钟的时间走过这条路。
输入保证至少存在1条商店到赛场的路线。

 

 

Output

对于每组输入,输出一行,表示工作人员从商店走到赛场的最短时间

 

 

Sample Input

 

2 11 2 33 31 2 52 3 53 1 20 0

 

 

Sample Output

 

32

裸题,直接上代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxx=999999999;
const int INF=110;
int n,m;
int mapp[INF][INF];
int dis[INF];
bool visited[INF];
void Dijkstra(int v0)
{
    for(int i=1; i<=n; i++){
        dis[i]=mapp[1][i];
        visited[i]=0;
    }
    visited[v0]=1;
    for(int i=1; i<=n; i++){
        int p,minn=maxx;
        for(int j=1; j<=n; j++){
            if(!visited[j] && dis[j]<minn){
                p=j;
                minn=dis[j];
            }
        }
        visited[p]=1;
        for(int j=1; j<=n; j++){
            if(!visited[j] && dis[p]+mapp[p][j]<dis[j]){
                dis[j]=dis[p]+mapp[p][j];
            }
        }
    }
    return ;
}
int main()
{
    while(cin>>n>>m){
        if(n==0 && m==0)  break;
        int a,b,c;
        for(int i=1; i<=n; i++){
            for(int j=1; j<=n; j++){
                mapp[i][j]=maxx;
            }
        }
        for(int i=1; i<=m; i++){
            cin>>a>>b>>c;
            mapp[a][b]=mapp[b][a]=c;
        }
        Dijkstra(1);
        cout<<dis[n]<<endl;
    }
    return 0;
}

再来一道不怎么裸的题

 

6487: Cosmic Rays

时间限制: 1 Sec  内存限制: 128 MB
提交: 85  解决: 43
[提交][状态][讨论版][命题人:admin]

题目描述

On the xy-plane, Snuke is going to travel from the point (xs,ys) to the point (xt,yt). He can move in arbitrary directions with speed 1. Here, we will consider him as a point without size.
There are N circular barriers deployed on the plane. The center and the radius of the i-th barrier are (xi,yi) and ri, respectively. The barriers may overlap or contain each other.
A point on the plane is exposed to cosmic rays if the point is not within any of the barriers.
Snuke wants to avoid exposure to cosmic rays as much as possible during the travel. Find the minimum possible duration of time he is exposed to cosmic rays during the travel.

Constraints
All input values are integers.
−109≤xs,ys,xt,yt≤109
(xs,ys) ≠ (xt,yt)
1≤N≤1,000
−109≤xi,yi≤109
1≤ri≤109

输入

The input is given from Standard Input in the following format:
xs ys xt yt
N
x1 y1 r1
x2 y2 r2
:
xN yN rN

输出

Print the minimum possible duration of time Snuke is exposed to cosmic rays during the travel. (精确到小数点后9位)

样例输入

-2 -2 2 2
1
0 0 1

样例输出

3.656854249

提示

An optimal route is as follows:

 

求出从起点到终点走过的最短的不在圆上的距离

因为要尽量在圆内走,所以将每个圆心都看做一个可以走的点,计算出点与点之间的距离,存在二维数组里,这样就变成了最短路的题

代码:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e3+10;
const int INF = 2e9; 
bool vis[MAXN];
double val[MAXN][MAXN];
double ans[MAXN];
struct node {
    int x, y, r;
} e[MAXN];

void Dijkstra( int n, int beg) {
    for (int i = 0; i < n; i++) {
        ans[i] = INF;
        vis[i] = false;
    }
    ans[beg] = 0;
    for (int j = 0; j < n; j++) {
        int k = -1;
        double  min = INF;
        for (int i = 0; i < n; i++) {
            if (!vis[i] && ans[i] < min) {
                min = ans[i];
                k = i;
            }
        }
        if (k == -1) {
            break;
        }
        vis[k] = true;
        for (int i = 0; i < n; i++) {
            if (!vis[i] && ans[k] + val[k][i] < ans[i]) {
                ans[i] = ans[k] + val[k][i];
            }
        }

    }
}
int main() {
    int n;
    int sx, sy, ex, ey;
    cin >> sx >> sy >> e[0].x >> e[0].y >> n;
    e[0].r = 0;
    e[n + 1].r = 0;
    e[n + 1].x=sx;
    e[n+1].y=sy;
    n++;
    for (int i = 1; i < n; i++) {
        cin >> e[i].x >> e[i].y >> e[i].r;
    }
    for (int i = 0; i <= n; i++) {
        for (int j = i+1; j <= n; j++) {

            val[i][j] = (double)(sqrt((e[i].x - e[j].x)*(e[i].x - e[j].x) +(e[i].y - e[j].y)*(e[i].y - e[j].y)) - e[i].r - e[j].r);
            if(val[i][j]<0) val[i][j]=0;
            val[j][i] = val[i][j];
        }
    }
    Dijkstra(n + 1, n);
    printf("%.9f\n",ans[0]);
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值