最短路径问题(求单源最短路径)Dijkstra算法

求单源最短路径(边的权值非负)   -----Dijsktra算法

所谓单源最短路径就是固定一个顶点为源点 求源点到其他每个顶点的最短路径


在Dijkstra 算法里,为了求源点v0 到其他各顶点vi 的最短路径及其长度,需要设置3 个数组:

a) dist[n]:dist[i]表示当前找到的从源点v0 到终点vi 的最短路径的长度,初始时,dist[i]
为Edge[v0][i],即邻接矩阵的第v0 行。
b) S[n]:S[i]为0 表示顶点vi 还未加入到集合S 中,S[i]为1 表示vi 已经加入到集合S 中。
初始时,S[v0]为1,其余为0,表示最初集合S 中只有顶点v0。
c) path[n]:path[i]表示v0 到vi 的最短路径上顶点vi 的前一个顶点序号。采用“倒向追踪”
的方法,可以确定v0 到顶点vi 的最短路径上的每个顶点。


在Dijkstra 算法里,重复做以下3 步工作:
1) 在数组dist[n]里查找S[i] != 1,并且dist[i]最小的顶点u;
2) 将S[u]改为1,表示顶点u 已经加入进来了;
3) 修改T 集合中每个顶点vk 的dist 及path 数组元素值:当S[k] != 1,且顶点u 到顶点vk
有边(Edge[u][k]<MAX),且dist[u] + Edge[u][k] < dist[k],则修改dist[k]为dist[u] +
Edge[u][k],修改path[k]为u。


ZOJ 1298 POJ 1135

多米诺骨牌效应

计算最后倒下的是哪一张牌  在什么时间倒下

游戏中有一些关键牌  当关键牌倒下时  连接这张关键牌的所有行都开始倒下


思路:

最后倒下的牌有两种情形:

① 最后倒下的牌是关键牌,其时间及位置就是第1 张关键牌到其他关键牌中最短路
径的最大值及对应的关键牌;

② 最后倒下的牌是两张关键牌之间的某张普通牌,其时间为这两张
关键牌倒下时间的一半再加上及这一行倒下时间的一半,位置为这两张牌之间的某张普通牌(不
一定恰好是该行正中间的那张牌,但题目并不需要具体求出是哪张牌)。
本题的方法步骤如下:
a) 先计算每一张关键牌倒下的time[i]。这需要利用Dijkstra 算法求第1 张关键牌到其他每
张关键牌的最短路径。然后取time[i]的最大值,设为maxtime1。
b) 计算每一行完全倒下的时间。设每一行的两端的关键牌为i 和j,则这一行完全倒下的时
间为(time[i] + time[j] + Edge[i][j])/2.0,其中Edge[i][j]为连接第i、j 两张关键牌的行倒下
所花的时间。取所有行完全倒下时间的最大值,设为maxtime2。
c) 如果maxtime2 > maxtime1,则是第②种情形;否则是第①种情形。


代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>

#define eps 1e-8
#define op operator
#define MOD  10009
#define MAXN  100100
#define INF 0x7fffffff

#define FOR(i,a,b)  for(int i=a;i<=b;i++)
#define FOV(i,a,b)  for(int i=a;i>=b;i--)
#define REP(i,a,b)  for(int i=a;i<b;i++)
#define REV(i,a,b)  for(int i=a-1;i>=b;i--)
#define MEM(a,x)    memset(a,x,sizeof a)
#define ll __int64

using namespace std;
int n,m;
int edge[510][510];
int s[510];
int time[510];//代表第i张牌倒下的时间
int cs;

void Dijkstra()
{
    for(int i=0;i<n;i++)
    {
        time[i]=edge[0][i];
        s[i]=0;
    }
    time[0]=0; s[0]=1;
    for(int i=0;i<n-1;i++)//  从顶点0开始确定n-1条最短路径
    {
        int mi=INF, u=0;
        for(int j=0;j<n;j++)
        {
            if(!s[j]&&time[j]<mi)
            {
                u=j; mi=time[j];
            }
        }
        s[u]=1;
        for(int j=0;j<n;j++)
        {
            if(!s[j]&&edge[u][j]<INF&&time[u]+edge[u][j]<time[j])
            {
                time[j]=time[u]+edge[u][j];
            }
        }
    }
    double mx1=-(double)INF;
    int pos;
    for(int i=0;i<n;i++)
    {
        if(time[i]*1.0>mx1)
        {
            mx1=time[i]*1.0; pos=i;
        }
    }
    double mx2=-(double)INF,t; int pos1,pos2;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            t=(time[i]+time[j]+edge[i][j])/2.0;
            if(edge[i][j]<INF&&t>mx2)
            {
                pos1=i; pos2=j;
                mx2=t;
            }
        }
    }
    printf("System #%d\n",cs++);
    printf("The last domino falls after ");
    if(mx1>=mx2)
    {
        printf("%.1f seconds, at key domino %d.\n",mx1,pos+1);
    }
    else
    {
        printf("%.1f seconds, between key dominoes %d and %d.\n",mx2,pos1+1,pos2+1);
    }
    puts("");
}

int main()
{
//freopen("ceshi.txt","r",stdin);
    cs=1;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)
            break;
        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++)
                edge[i][j]=INF;
        for(int i=0;i<m;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            u--; v--;
            edge[u][v]=edge[v][u]=w;
        }

        Dijkstra();
    }
    return 0;
}


zoj 2750 成语接龙游戏

给出n个成语  每个成语由若干词构成  要将成语连接起来 下一个成语的第一个词要跟上一个成语的最后一个词

在词典中查找成语需要花时间  所花的时间为该成语前的一个数字的值

首先就是建图 如果一个成语的最后一个词跟另外一个成语的第一个词相同就有一条边

边的权值为所花的时间 求最短路即可

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>

#define eps 1e-8
#define op operator
#define MOD  10009
#define MAXN  1010
#define INF 0x7fffffff
#define MEM(a,x)    memset(a,x,sizeof a)
#define ll __int64

using namespace std;

struct node
{
    char fro[5],bak[5];
    int val;
};
node no[MAXN];
int Edge[MAXN][MAXN];
int dis[MAXN];
int S[MAXN];

int main()
{
//freopen("ceshi.txt","r",stdin);
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        if(n==0)  break;
        for(int i=0;i<n;i++)
        {
            char ch[1000];
            scanf("%d%s",&no[i].val,ch);
            int len=strlen(ch);
            for(int k=0,j=len-1;k<4;k++,j--)
            {
                no[i].fro[k]=ch[k];
                no[i].bak[3-k]=ch[j];
            }
            no[i].fro[4]='\0';
            no[i].bak[4]='\0';
        }
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<n;j++)
            {
                Edge[i][j]=INF;
                if(i==j)  continue;
                if(strcmp(no[i].bak,no[j].fro)==0)
                {
                    Edge[i][j]=no[i].val;
                }
            }
        }
        for(int i=0;i<n;i++)
        {
            dis[i]=Edge[0][i];
            S[i]=0;
        }
        //Dijkstra
        S[0]=1;dis[0]=0;
        for(int i=0;i<n-1;i++)
        {
            int mi=INF,u=0;
            for(int j=0;j<n;j++)
            {
                if(!S[j]&&dis[j]<mi)
                {
                    u=j; mi=dis[j];
                }
            }
            S[u]=1;
            for(int j=0;j<n;j++)
            {
                if(!S[j]&&Edge[u][j]<INF&&dis[u]+Edge[u][j]<dis[j])
                {
                    dis[j]=dis[u]+Edge[u][j];
                }
            }
        }
        if(dis[n-1]==INF)
            puts("-1");
        else printf("%d\n",dis[n-1]);
    }
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值