Dijkstra 算法

1,算法步骤:

a.初始时,S只包含源点,即S={v},v的距离为0。U包含除v外的其他顶点,即:U={其余顶点},若v与U中顶点u有边,则<u,v>正常有权值,若u不是v的出边邻接点,则<u,v>权值为∞。

b.从U中选取一个距离v最小的顶点k,把k,加入S中(该选定的距离就是v到k的最短路径长度)。

c.以k为新考虑的中间点,修改U中各顶点的距离;若从源点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值的顶点k的距离加上边上的权。

d.重复步骤b和c直到所有顶点都包含在S中。

2,说的很抽象,我也不是很理解,多做几道模板题,会慢慢理解的!

A - 温习最短路1

Description

某省自从实行了很多年的畅通工程计划后,终于修建了很多路。不过路多了也不好,每次要从一个城镇到另一个城镇时,都有许多种道路方案可以选择,而某些方案要比另一些方案行走的距离要短很多。这让行人很困扰。 

现在,已知起点和终点,请你计算出要从起点到终点,最短需要行走多少距离。

Input

本题目包含多组数据,请处理到文件结束。 
每组数据第一行包含两个正整数N和M(0<N<200,0<M<1000),分别代表现有城镇的数目和已修建的道路的数目。城镇分别以0~N-1编号。 
接下来是M行道路信息。每一行有三个整数A,B,X(0<=A,B<N,A!=B,0<X<10000),表示城镇A和城镇B之间有一条长度为X的双向道路。 
再接下一行有两个整数S,T(0<=S,T<N),分别代表起点和终点。

Output

对于每组数据,请在一行里输出最短需要行走的距离。如果不存在从S到T的路线,就输出-1

Sample Input

3 3

0 1 1

0 2 3

1 2 1

0 2

3 1

0 1 1

1 2

Sample Output

   
   
2 -1

是模板题,可自己不会做,学长的代码,自己加上注释,以便日后理解,随后会贴上自己写的Dijkstra 算法题的代码!

现在先纪念一下:

#include<stdio.h>
#include<string.h>
#define MAX 99999
int n,m ,i,j,k;
int map[1007][1007];//代表两点之间的距离
int visit[1007];//代表节点是否被访问过
int dis[1007];//代表两点之间的距离
int dijstra(int x,int y)//x代表起点,y代表终点
{
    int min;
    memset(visit,0,sizeof(visit));//开始都没访问


    for(i=0;i<n;i++)//这一个for循环的作用是初始化,从主函数调过来
    {
        dis[i]=map[x][i];//让dis[]默认的,为节点到起点的距离
    }


    dis[x]=0;//起点到起点的距离是0
    visit[x]=1;//起点被访问过,标记为1


    for(i=0;i<n;i++)//遍历所有的节点
    {
        min=MAX;
        for(j=0;j<n;j++)//这一个for循环的作用是,从起点开始,遍历所有的节点
        {
            if(!visit[j]&&dis[j]<min)//所有没访问的,并且距离最短的,则节点之间的距离就更新
            {
                min=dis[j];
                k=j;//并把访问的节点标记下来
            }
        }
        visit[k]=1;//代表已访问
        for(j=0;j<n;j++)//这一个for循环的作用是,从第一个for循环得到的,离起点最短的节点开始,遍历所有的节点
        {
            if(!visit[j]&&dis[j]>min+map[k][j])          //比较
                                   //k是起点,j是终点    //起点到第三个点的直接距离
                                                         //与
                                                         //上一个for循环得到起点到第2个节点最短距离+第2个节点与第3个节点距离
                                                         //最小值
            {
                dis[j]=min+map[k][j];
            }
        }
    }
    return dis[y];
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=0;i<n;i++)//这一个for循环的作用是初始化,让所有两点之间的距离无穷大
        {
            for(j=0;j<n;j++)
            {
                map[i][j]=map[j][i]=MAX;
            }
        }
        while(m--)
        {
            int a,b,distance;
            scanf("%d%d%d",&a,&b,&distance);//更新两点之间的距离
            if(map[a][b]>distance)
            {
                map[a][b]=map[b][a]=distance;
            }
        }
        int begin,end;
        scanf("%d%d",&begin,&end);
        int ans=dijstra(begin,end);
        if(ans==MAX)
            printf("-1\n");
        else
            printf("%d\n",ans);
    }
    return 0;
}

这是自己做的,因为和上一题类似,所以思路,代码都差不多

B - 温习最短路2

Description

Bessie is out in the field and wants to get back to the barn to get as much sleep as possible before Farmer John wakes her for the morning milking. Bessie needs her beauty sleep, so she wants to get back as quickly as possible. 

Farmer John's field has N (2 <= N <= 1000) landmarks in it, uniquely numbered 1..N. Landmark 1 is the barn; the apple tree grove in which Bessie stands all day is landmark N. Cows travel in the field using T (1 <= T <= 2000) bidirectional cow-trails of various lengths between the landmarks. Bessie is not confident of her navigation ability, so she always stays on a trail from its start to its end once she starts it. 

Given the trails between the landmarks, determine the minimum distance Bessie must walk to get back to the barn. It is guaranteed that some such route exists.

Input

* Line 1: Two integers: T and N 

* Lines 2..T+1: Each line describes a trail as three space-separated integers. The first two integers are the landmarks between which the trail travels. The third integer is the length of the trail, range 1..100.

Output

* Line 1: A single integer, the minimum distance that Bessie must travel to get from landmark N to landmark 1.

Sample Input

5 5
1 2 20
2 3 30
3 4 20
4 5 20
1 5 100

Sample Output

90

Hint

INPUT DETAILS: 

There are five landmarks. 

OUTPUT DETAILS: 

Bessie can get home by following trails 4, 3, 2, and 1.

#include<stdio.h>
#include<string.h>
#define MAX 99999
int visit[1007],dis[1007],map[1007][1007];
int i,j,k,m,n,t;
int Dijkstra(int s,int e)
{
    int min;
    memset(visit,0,sizeof(visit));
    for(i=1;i<=n;i++)
    {
        dis[i]=map[s][i];
    }
    dis[s]=0;
    visit[s]=1;
    for(i=1;i<=n;i++)
    {
        min=MAX;
        for(j=1;j<=n;j++)
        {
            if(!visit[j]&&dis[j]<min)
            {
                min=dis[j];
                k=j;
            }
        }
        visit[k]=1;
        for(j=1;j<=n;j++)
        {
            if(!visit[j]&&dis[j]>min+map[k][j])
            {
                dis[j]=min+map[k][j];
            }
        }

    }
    return dis[e];
}
int main()
{
    while(scanf("%d%d",&t,&n)==2)
    {
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                map[i][j]=map[j][i]=MAX;
            }
        }
        while(t--)
        {
            int a,b,distance;
            scanf("%d%d%d",&a,&b,&distance);
            if(map[a][b]>distance)
                map[a][b]=map[b][a]=distance;
        }
            int ans=Dijkstra(1,n);
            printf("%d\n",ans);
    }
    return 0;
}

这也是模板题,重在熟悉,理解

最短路

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


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 1 1 2 3 3 3 1 2 5 2 3 5 3 1 2 0 0
 

Sample Output
  
  
3 2

#include<stdio.h>
#include<string.h>
#define MAX 99999
int visit[1007],dis[1007],map[1007][1007];
int i,j,k,m,n;
int dijkstra(int s,int e)
{
    int min;
    memset(visit,0,sizeof(visit));
    for(i=1;i<=n;i++)
    {
        dis[i]=map[s][i];
    }
    dis[s]=0;
    visit[s]=1;
    for(i=1;i<=n;i++)
    {
        min=MAX;
        for(j=1;j<=n;j++)
        {
           if(!visit[j]&&dis[j]<min)
           {
               min=dis[j];
               k=j;
           }
        }
        visit[k]=1;
        for(j=1;j<=n;j++)
        {
            if(!visit[j]&&dis[j]>min+map[k][j])
                dis[j]=min+map[k][j];
        }
    }
    return dis[e];
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(m==0&&n==0)
            return 0;
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                map[i][j]=map[j][i]=MAX;
            }
        }
        while(m--)
        {
            int a,b,distance;
            scanf("%d%d%d",&a,&b,&distance);
            if(map[a][b]>distance)
            {
                map[a][b]=map[b][a]=distance;
            }

        }
        int ans=dijkstra(1,n);
        printf("%d\n",ans);
    }
    return 0;
}

这道题与之前的有不一样,没有给出起点和终点,其实一次dijkstra即可,我们将草儿家看成0,从家到相邻的时间看成0,我们只需求家到各个目的地的最短距离即可


一个人的旅行

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 18430    Accepted Submission(s): 6406


Problem Description
虽然草儿是个路痴(就是在杭电待了一年多,居然还会在校园里迷路的人,汗~),但是草儿仍然很喜欢旅行,因为在旅途中 会遇见很多人(白马王子,^0^),很多事,还能丰富自己的阅历,还可以看美丽的风景……草儿想去很多地方,她想要去东京铁塔看夜景,去威尼斯看电影,去阳明山上看海芋,去纽约纯粹看雪景,去巴黎喝咖啡写信,去北京探望孟姜女……眼看寒假就快到了,这么一大段时间,可不能浪费啊,一定要给自己好好的放个假,可是也不能荒废了训练啊,所以草儿决定在要在最短的时间去一个自己想去的地方!因为草儿的家在一个小镇上,没有火车经过,所以她只能去邻近的城市坐火车(好可怜啊~)。
 

Input
输入数据有多组,每组的第一行是三个整数T,S和D,表示有T条路,和草儿家相邻的城市的有S个,草儿想去的地方有D个;
接着有T行,每行有三个整数a,b,time,表示a,b城市之间的车程是time小时;(1=<(a,b)<=1000;a,b 之间可能有多条路)
接着的第T+1行有S个数,表示和草儿家相连的城市;
接着的第T+2行有D个数,表示草儿想去地方。
 

Output
输出草儿能去某个喜欢的城市的最短时间。
 

Sample Input
  
  
6 2 3 1 3 5 1 4 7 2 8 12 3 8 4 4 9 12 9 10 2 1 2 8 9 10
 

Sample Output
  
  
9

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int inf = 1<<30;

int T,S,D,n;
int map[1111][1111];
int vis[1111],cast[1111];
int s[1111],e[1111];

void Dijkstra()
{
    int i,j,minn,pos;
    memset(vis,0,sizeof(vis));
    vis[0] = 1;
    for(i = 0; i<=n; i++)
        cast[i] = map[0][i];
    for(i = 1; i<=n; i++)
    {
        minn = inf;
        for(j = 1; j<=n; j++)
        {
            if(cast[j]<minn && !vis[j])
            {
                pos = j;
                minn = cast[j];
            }
        }
        vis[pos] = 1;
        for(j = 1; j<=n; j++)
        {
            if(cast[pos]+map[pos][j]<cast[j] && !vis[j])
                cast[j] = cast[pos]+map[pos][j];
        }
    }
}

int main()
{
    int i,j,x,y,z,start,end;
    while(scanf("%d%d%d",&T,&S,&D))
    {
        n = 0;
        for(i = 0; i<1111; i++)
        {
            for(j = 0; j<1111; j++)
                map[i][j] = inf;
        }
        while(T--)
        {
            scanf("%d%d%d",&x,&y,&z);
            n = max(max(n,x),y);
            if(z<map[x][y])
                map[x][y] = map[y][x] = z;
        }
        int minn = inf;
        for(i = 0; i<S; i++)
        {
            scanf("%d",&s[i]);
            map[0][s[i]] = map[s[i]][0] = 0;
        }
        for(i = 0; i<D; i++)
            scanf("%d",&e[i]);
        Dijkstra();
        for(i = 0; i<D; i++)
            minn = min(minn,cast[e[i]]);
        printf("%d\n",minn);
    }

    return 0;
}




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值