九度OJ 题目1008:最短路径问题

一题目描述:
给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。
输入:
输入n,m,点的编号是1~n,然后是m行,每行4个数 a,b,d,p,表示a和b之间有一条边,且其长度为d,花费为p。最后一行是两个数 s,t;起点s,终点t。n和m为0时输入结束。
(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算法。

   需要提醒的地方是有两处,一是注意题中的要求,在出现多条最短路径时,选择代价最小的一条。满足此要求,需要改进两个地方,在输入时,有可能出现两个点v1,v2之间两条道路,距离相等,但是代价不等,因此输入时需要做代价判断更新(看了题解时才想到这点);另外,在在更新dist数组时,不仅在出现更短距离时需要更新,同时当距离相等时,出现更小代价时也需要更新,这点很容易想到。

    二是注意最大值的设定,题中并没有给出最大值的上限,因此我们需要考虑int型的最大值作为INF(本代码中是maxint),int型是4个字节,即32位,有符号范围的最大值是0x7fffffff,map[i][j]用此最大值作为上限需要格外小心,因为在更新dist数组中一旦做加法便会溢出,解决方法有两个,可以采用先判断在做加法的方法,判断map[i][j]<INF是否成立,当map[i][j]=INF时,其实并不需要在继续加了,它本身就是去穷大了,不需要更新数组;或者在加法的时候将map[i][j]中的值先转换成64位的变量,之后再做加法,以下分别会给出代码。

    注:在Windows的内存管理机制中,进程的所有使用的地址都是虚拟地址,进程也是运行在虚拟内存中的,虚拟内存的地址和物理内存中的地址通过页表进行转换。在32位Windows中,能够表示的最大寻址范围就是4G,每一个进程都独享4G的虚拟内存。而Windows采取是这样子分配的:将4G空间分成两部分,低2G的部分是给用户使用的,而高2G的部分是保留给系统使用的。这样子,每一个进程真正能够使用的内存就只有2G。而这个2G,包括了栈和堆,以及存放常量和静态数据的区域。2G 内存大小限制是Windows(32位)的限制搜索,是没有办法超越的。

三.代码

#include <stdio.h>
#include <stdlib.h>
#define MAX 1024
#define maxint 0x7fffffff   //定义int型最大值
int e,v,map[MAX][MAX],cost[MAX][MAX];

void Dijkstra(int start,int *dist,int *co)
{
    int i,j,k,minl,minu;
    int visit[MAX];

    //init
    for(i=0;i<v;i++)
    {
        dist[i]=map[start][i];
        co[i]=cost[start][i];
        visit[i]=0;    //所有的点未加入S集合中
    }

    visit[start]=1;  //初始点加入S集合中
    dist[start]=0;

    //find min dist
    for(i=1;i<v;i++)     //将剩下n-1个点也依次选取最小的dist加入S集合中
    {
        minl=maxint;
        for(j=0;j<v;j++)    //选取最小的dist
        {
            if(!visit[j]&&dist[j]<minl)
            {
                minu=j;
                minl=dist[j];
            }
        }

        //visit j
        visit[minu]=1;

        //update dist
        for(j=0;j<v;j++)
        {
            if(!visit[j]&&(map[minu][j]<maxint)&&(dist[minu]+map[minu][j]<dist[j]))
            {
                dist[j]=dist[minu]+map[minu][j];
                co[j]=co[minu]+cost[minu][j];
            }
            else if(!visit[j]&&(map[minu][j]<maxint)&&(dist[minu]+map[minu][j]==dist[j])&&(co[minu]+cost[minu][j]<co[j]))   //多条最短距离,更新最小代价
                co[j]=co[minu]+cost[minu][j];
                
                
            /*  网上看到的解法
                    __int64 temp1=p[xx].dis+c[xx][yy].dis;  
                    __int64 temp2=p[xx].cost+c[xx][yy].cost;  
                    if(!vis[yy]&&(temp1<p[yy].dis||(temp1==p[yy].dis&&temp2<p[yy].cost)))  
                    {  
                        p[yy].dis=temp1;  
                        p[yy].cost=temp2;  
                    }  

            */
        }
    }
}

int main()
{
    int i,j,v1,v2,start,end,p1,p2;
    int dist[MAX],co[MAX];

    freopen("1008.txt","r",stdin);

    while(scanf("%d%d",&v,&e)&&(v||e))
    {
        //init
        for(i=0;i<v;i++)
        {
            for(j=0;j<v;j++)
            {
                map[i][j]=maxint;
                cost[i][j]=maxint;  //add
            }
        }

        //input
        for(i=0;i<e;i++)
        {
            scanf("%d%d%d%d",&v1,&v2,&p1,&p2);

            if(map[v1-1][v2-1]>p1)
            {
                map[v1-1][v2-1]=p1;
                map[v2-1][v1-1]=p1;
                cost[v1-1][v2-1]=p2;
                cost[v2-1][v1-1]=p2;
            }
            else if(map[v1-1][v2-1]==p1&&cost[v1-1][v2-1]>p2)   //输入在距离相等时,更新最小的代价
            {
                cost[v1-1][v2-1]=p2;
                cost[v2-1][v1-1]=p2;
            }

        }

        scanf("%d%d",&start,&end);

        Dijkstra(start-1,dist,co);   //起点,距离数组,代价数组

        printf("%d %d\n",dist[end-1],co[end-1]);
    }

    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值