PAT甲级刷题记录——1030 Travel Plan (30分)

A traveler’s map gives the distances between cities along the highways, together with the cost of each highway. Now you are supposed to write a program to help a traveler to decide the shortest path between his/her starting city and the destination. If such a shortest path is not unique, you are supposed to output the one with the minimum cost, which is guaranteed to be unique.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 4 positive integers N, M, S, and D, where N (≤500) is the number of cities (and hence the cities are numbered from 0 to N−1); M is the number of highways; S and D are the starting and the destination cities, respectively. Then M lines follow, each provides the information of a highway, in the format:

City1 City2 Distance Cost

where the numbers are all integers no more than 500, and are separated by a space.

Output Specification:

For each test case, print in one line the cities along the shortest path from the starting point to the destination, followed by the total distance and the total cost of the path. The numbers must be separated by a space and there must be no extra space at the end of output.

Sample Input:

4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20

Sample Output:

0 2 3 3 40

思路

这题相比于PBM那道来说就简单很多了,但是很恐怖,怎么个恐怖法呢,就算样例过了,还是三个测试点全错,后来找到了原因:记录花费的时候也要双边记录(因为这是一张无向图,不能只记一个方向的边权)。

题目意思很常规,给出顶点数N,边数M,起点S,终点D,要你计算最短路,如果有多条最短路,那么选择花费最少的那条。因为只有两个标尺,所以我这里推荐直接在Dijkstra里处理,然后只要用DFS回溯输出路径即可。

因此,只要在优化更新d[v]的时候,同时更新花费c[v]和前驱pre[v],如果d[u]+G[u][j].dis==d[v],那么就进行第二标尺的判断,如果此时的花费更少,这条路就是我们要的,于是更新花费c[v]和前驱pre[v]。

最后,只要在DFS里一直递归找到起点,然后从起点开始输出就是我们要的路径了。

当然,这题也能用Dijkstra+DFS的方法做(这样的话Dijkstra里只要处理前驱的问题,然后再在DFS函数里对某条最短路进行花费上的处理)。

代码

#include<cstdio>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<string>
#include<iostream>
using namespace std;
const int maxn = 501;
const int INF = 123123123;
struct node{
    int v;//目标点
    int dis;//边权
};
vector<node> G[maxn];
vector<int> path, tempPath;
int cost[maxn][maxn];//两点间的花费
int c[maxn];//起点到某点的最少花费
int pre[maxn] = {0};
int d[maxn] = {0};
bool vis[maxn] = {false};
void Dijkstra(int n, int s){
    fill(d, d+maxn, INF);
    for(int i=0;i<maxn;i++) pre[i] = i;//初始化前驱
    d[s] = 0;
    c[s] = 0;//起点最少花费为0
    for(int i=0;i<n;i++){
        int u = -1;
        int MIN = INF;
        for(int j=0;j<n;j++){
            if(vis[j]==false&&d[j]<MIN){
                u = j;
                MIN = d[j];
            }
        }
        if(u==-1) return;
        vis[u] = true;
        for(int j=0;j<G[u].size();j++){
            int v = G[u][j].v;
            if(vis[v]==false){
                if(d[u]+G[u][j].dis<d[v]){
                    d[v] = d[u]+G[u][j].dis;
                    c[v] = c[u]+cost[u][v];//加上u->v的花费
                    pre[v] = u;
                }
                else if(d[u]+G[u][j].dis==d[v]){
                    if(c[u]+cost[u][v]<c[v]){
                        c[v] = c[u]+cost[u][v];
                        pre[v] = u;
                    }
                }
            }
        }
    }
}
void dfs(int v, int s){
    if(v==s){
        printf("%d ", v);
        return;
    }
    dfs(pre[v], s);
    printf("%d ", v);
}
int main(){
    int N, M, S, D;
    scanf("%d%d%d%d", &N, &M, &S, &D);
    for(int i=0;i<M;i++){
        node tmp;
        int a, b, tmpdis, tmpcost;
        scanf("%d%d%d%d", &a, &b, &tmpdis, &tmpcost);
        tmp.dis = tmpdis;
        tmp.v = a;
        G[b].push_back(tmp);
        tmp.v = b;
        G[a].push_back(tmp);
        cost[a][b] = tmpcost;//a->b花费tmpcost
        cost[b][a] = tmpcost;//不要忘了这句话,因为这是个无向图的边权
    }
    Dijkstra(N, S);
    dfs(D, S);
    printf("%d %d", d[D], c[D]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值