8.21 问题 D: 最短路径问题问题 D: 最短路径问题

问题 D: 最短路径问题

题目描述

给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。

输入

输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示ab之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点tnm0时输入结束。
(1<n<=1000, 0<m<100000, s != t)

输出

输出 一行有两个数, 最短距离及其花费。

样例输入

3 2

1 2 5 6

2 3 4 5

1 3

0 0

样例输出

9 11

提示

拿到这题,第一印象就是最短路劲问题(题目写得清清楚楚)。当然,你可以直接套用最短路劲的解法。不过这里我要给大家介绍另一种解法,同样是图论里的算法——深度优先搜索。

 

 

从起点开始进行深度优先搜索,当搜索的结点到达终点时查看路径总长度与花费是否比已经得到的最短路径和最小花费小,如果要小的话就使用当前的路径和花费取代最短路径和最小花费。

 

当遍历到终点时是否就结束了?非也,还需要从其他路径遍历,判断其他路径是否又更短花费更小的。这里就需要用到回溯了。所谓回溯,就是还需要往回走来走其他的路径。那么会不会进入循环状态呢?对遍历过的结点进行标记就能够杜绝循环。当然需要在回溯时取消之前的标记。

 

思路:Dijkstra算法的一个简单题,计算最小路径时同时当路径长度相同时比较花费,找最小的即可。



#include<stdio.h>
#include<string.h>
int a[1100][1100],book[1100],d[1100],c[1100][1100],s[1100];
int main()
{
    int i,j,k,m,n;
    int max=1e9,min,sum;
    int t1,t2,t3,t4,s1,t;
    while(scanf("%d%d",&n,&m),m+n!=0)
    {
        memset(book,0,sizeof(book));
        memset(d,0,sizeof(d));
        memset(s,0,sizeof(s));
        for(i=1;i<=n;i++)//初始化数据
        {
            for(j=1;j<=n;j++)
            {
                if(i==j)
                    a[i][j]=0;
                else
                    a[i][j]=max;
            }
        }
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d%d",&t1,&t2,&t3,&t4);
            if(t3<a[t1][t2])
            {
                a[t1][t2]=t3;
                a[t2][t1]=t3;//双向存储路径长度
                c[t1][t2]=t4;
                c[t2][t1]=t4;//同时双向存储花费
                 
            }   
        }
        scanf("%d%d",&s1,&t);
        for(i=1;i<=n;i++)
        {
            d[i]=a[s1][i];
            s[i]=c[s1][i];
        }
        book[s1]=1;
        int c1=1;
        sum=0;
        while(c1<n)//算法
        {
            min=max;
            for(i=1;i<=n;i++)
            {
                if(book[i]==0&&d[i]<min)
                {
                    min=d[i];
                    j=i;
                }
            }
            c1++;
            book[j]=1;
            for(i=1;i<=n;i++)
            {
                if(book[i]==0)
                {
                    if(d[i]>a[j][i]+d[j])//优先判断路径
                    {
                        d[i]=a[j][i]+d[j];
                        s[i]=c[j][i]+s[j];
                    }
                    if(d[i]==a[j][i]+d[j])//路径长度相等时判断花费
                    {
                        if(s[i]>c[j][i]+s[j])//路径长度相等取比较小的花费
                        {
                            d[i]=a[j][i]+d[j];
                            s[i]=c[j][i]+s[j];
                        }
                    }   
                }
            }
        }
        printf("%d %d\n",d[t],s[t]);
    }
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值