JOBDU-OJ 1008 最短路径问题

本文通过一道OJ题目介绍了使用Dijkstra算法解决最短路径问题,强调了在实现过程中需要注意的细节,包括当距离相同时优先选择花费较少的路径。作者分享了在解题过程中的错误和教训,如数组大小设置、初始化标记数组的重要性以及对vector和Dijkstra算法的理解加深。

题目描述:
给你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
来源:
2010年浙江大学计算机及软件工程研究生机试真题


太坑了,被不细心坑了一晚上

分析:
这是一道求单源最短路径的题,显然要使用dijkstra算法。有一点要注意的是:

1.以中间点更新最短路线时,如果距离相同,要选择最少花费的路线
2.选择新的中间点加入已经求得最小路径的点的集合时,如果距离相同,要选择最少花费的点 ( 其实这条可以忽略,因为当有若干个点的距离同时相等时,不管他们的花费如何,接下来他们都会依次地被加入,因为很容易证明,随后的更新不可能再找到比这个距离更小的路径了)

提交了好几次有RE也有WA。RE是因为题目的数据范围我没看清,导致数组开太小了。后来一直WA,一直找不到原因,看了其他人的代码发现上述注意事项里的第二条,添加了之后还是不对。近乎抓狂。。。最后发现是忘记初始化mark数组了。。。。。。。

附上源码:

#include <stdio.h>
#include <vector>
using namespace std;

#define MAXN 1001
#define MAXM 100001
#define INF 0x7fffffff

int n,m,s,t;

bool mark[MAXN];
int dis[MAXN];
int price[MAXN];

struct Edge{
    int next;
    int d;
    int p;
};

vector<Edge> edge[MAXM];    //邻接链表




void dijkstra(int s, int t){

    int currentPoint = s;   //设置起点为当前中间点
    mark[s] = true;                 //标记起点已经找到最短路径
    dis[s] = 0;             //起点到起点的最短路径为0
    price[s] = 0;                   //起点到起点的花费为0
    int tmp;

    while(m--){

        for(int i = 0; i<edge[currentPoint].size();i++){    //访问当前中间点的所有边
            tmp = edge[currentPoint][i].next;               //取得该边另一头的节点
            if(mark[tmp]){                                  //如果已经找到最短路径了,舍弃
                continue;
            }else{
                if ( dis[tmp] > (dis[currentPoint] + edge[currentPoint][i].d) ){ 
                    //如果当前到达该节点的最小距离大于通过中间点currentPoint到达该点的距离,则更新

                    dis[tmp] = dis[currentPoint] + edge[currentPoint][i].d;
                    price[tmp] = price[currentPoint] + edge[currentPoint][i].p;

                }else if(dis[tmp] == (dis[currentPoint] + edge[currentPoint][i].d) &&
                    price[tmp] > price[currentPoint] + edge[currentPoint][i].p){

                    //如果距离相同,再判断是否要更新最小花费
                    price[tmp] = price[currentPoint] + edge[currentPoint][i].p;

                }
            }
        }

        //更新完该中间点的所有相邻的点后,在当前所有未找到最短路径的点中找到一个路径最小的点,
        //设置为新的当前中间点,并标记它找到了最短路径

        int tmpPoint = -1;
        int tmpMin = INF;
        for(int j=1; j<=n;j++){
            if(!mark[j]){
                if( dis[j] != tmpMin){
                    if(dis[j] < tmpMin){
                        tmpMin = dis[j];
                        tmpPoint = j;
                    }
                }else if(price[tmpPoint] > price[j])
                    tmpPoint = j;
            }
        }
        currentPoint = tmpPoint;
        mark[currentPoint] = true;

    }

}

int main(){
    int a,b,d,p;
    Edge tmp;

    while( scanf("%d%d", &n,&m) != EOF){
        if(m==0 && n==0)
            break;

        for( int j=1; j<=n; j++){   
            edge[j].clear();        //初始化邻接链表
            dis[j] = INF;           //初始化距离和花费
            price[j]   = INF;
            mark[j] = false;        //初始化mark,每个点都没访问过   (太坑啦!)
        }

        for( int i=0; i< m; i++){
            scanf("%d%d%d%d", &a,&b,&d,&p);
            //无向图要存储两个点的邻接链表
            tmp.next = b;
            tmp.d = d;
            tmp.p = p;

            edge[a].push_back(tmp);

            tmp.next = a;
            edge[b].push_back(tmp);

        }

        scanf("%d%d", &s,&t);

        dijkstra(s,t);

        printf("%d %d\n", dis[t], price[t]);
    }
    return 0;
}

总结:
1.一定要细心啊
2.debug能力有待提高
3.对vector的使用和dijkstra算法有了一定的了解

睡觉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值