【PAT A1030】Travel Plan

【PAT A1030】Travel Plan

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

/*
 * 【PAT A1030】Travel Plan
 * 解法1:Dijkstra
 * */
#include "cstdio"
#include "cstring"
#include "algorithm"
using namespace std;
const int MAXV=510;
const int INF=1000000000;//10^9无穷大
/*
 * n 顶点数 m 边数 st ed 起点 终点
 * G 距离矩阵 cost 花费矩阵
 * d[] 记录最短距离 c[] 记录最小花费
 * pre[] 前驱节点
 * */
int n,m,st,ed,G[MAXV][MAXV],cost[MAXV][MAXV];
int d[MAXV],c[MAXV],pre[MAXV];
bool vis[MAXV]={false};//顶点i是否被访问

void Dijkstra(int s)
{
    fill(d,d+MAXV,INF);
    fill(c,c+MAXV,INF);
    for(int i=0;i<n;i++)
    {
        pre[i]=i;//前驱节点默认为自身
    }
    d[s]=0;//起点s到达自身距离为0
    c[s]=0;//花费为0
    for(int i=0;i<n;i++)
    {
        //循环n次
        int u=-1,MIN=INF; //中介节点u MIN存放最短距离d[u]
        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;//找到距离最小节点u 设置为已访问
        for(int v=0;v<n;v++)
        {
            //如果节点v未访问并且u能到达v
            if(vis[v]== false&&G[u][v]!=INF)
            {
                if(d[u]+G[u][v]<d[v])
                {
                    //以u为中介节点能使起点到v的d[v]变小
                    d[v]=d[u]+G[u][v];//更新 d[] c[]
                    c[v]=c[u]+cost[u][v];
                    pre[v]=u;//u的前驱变为v
                }
                else if(d[u]+G[u][v]==d[v])
                {
                    //长度相同 有多条路径 选择c[v]最小的
                    if(c[u]+cost[u][v]<c[v])
                    {
                        c[v]=c[u]+cost[u][v];
                        pre[v]=u;
                    }
                }

            }
        }
    }

}
//打印路径
void DFS(int v)
{
    if(v==st)
    {
        printf("%d ",v);
        return;
    }
    DFS(pre[v]);//递归访问前驱
    printf("%d ",v);
}
int main(){
    scanf("%d%d%d%d",&n,&m,&st,&ed);
    int u,v;
    fill(G[0],G[0]+MAXV*MAXV,INF);//初始化图G
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&u,&v);
        scanf("%d%d",&G[u][v],&cost[u][v]);
        G[v][u]=G[u][v];//无向边
        cost[v][u]=cost[u][v];

    }
    Dijkstra(st);//执行算法
    DFS(ed);//打印路径 逆序递归
    printf("%d %d\n",d[ed],c[ed]); //打印最短路径最小花费
    return  0;

}
/*
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
 */
/*
 * 【PAT A1030】Travel Plan
 * 解法2:Dijkstra + DFS
 * */
#include "cstdio"
#include "cstring"
#include "algorithm"
#include "vector"

using namespace std;
const int MAXV = 510;
const int INF = 1000000000;//10^9无穷大
/*
 * n 顶点数 m 边数 st ed 起点 终点
 * G 距离矩阵 cost 花费矩阵
 * d[] 记录最短距离
 * minCost记录最短路径上最小花费
 * */
int n, m, st, ed, G[MAXV][MAXV], cost[MAXV][MAXV];
int d[MAXV], minCost = INF;
bool vis[MAXV] = {false};//顶点i是否被访问
vector<int> pre[MAXV];
vector<int> path, temppath;//最优路径 临时路径

void Dijkstra(int s) {
    fill(d, d + MAXV, INF);
    d[s] = 0;//起点s到达自身距离为0
    for (int i = 0; i < n; i++) {
        //循环n次
        int u = -1, MIN = INF; //中介节点u MIN存放最短距离d[u]
        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;//找到距离最小节点u 设置为已访问
        for (int v = 0; v < n; v++) {
            //如果节点v未访问并且u能到达v
            if (vis[v] == false && G[u][v] != INF) {
                if (d[u] + G[u][v] < d[v]) {
                    //以u为中介节点能使起点到v的d[v]变小
                    d[v] = d[u] + G[u][v];//更新 d[]
                    pre[v].clear();//清空v的前驱
                    pre[v].push_back(u); //v的前驱为u
                } else if (d[u] + G[u][v] == d[v]) {
                    //长度相同 有多条路径 选择c[v]最小的
                    pre[v].push_back(u); //v的前驱之一为u
                }

            }
        }
    }

}

//打印路径
void DFS(int v) {
    if (v == st)//到达递归边界
    {
        temppath.push_back(v);
        int tempCost = 0;

        for (int i = temppath.size() - 1; i > 0; i--)//倒着访问
        {
            //当前节点为id  下一个节点为idNext
            int id = temppath[i], idNext = temppath[i - 1];
            tempCost += cost[id][idNext];

        }

        if (tempCost < minCost) {//更新最小花费
            minCost = tempCost;
            path = temppath;
        }
        temppath.pop_back();
        return;
    }


    temppath.push_back(v);
    for (int i = 0; i < pre[v].size(); i++) {
        DFS(pre[v][i]);
    }
    temppath.pop_back();

}

int main() {
    scanf("%d%d%d%d", &n, &m, &st, &ed);
    int u, v;
    fill(G[0], G[0] + MAXV * MAXV, INF);//初始化图G
    fill(cost[0], cost[0] + MAXV * MAXV, INF);
    for (int i = 0; i < m; i++) {
        scanf("%d%d", &u, &v);
        scanf("%d%d", &G[u][v], &cost[u][v]);
        G[v][u] = G[u][v];//无向边
        cost[v][u] = cost[u][v];

    }
    Dijkstra(st);//执行算法
    DFS(ed);//打印路径 逆序递归
    for (int i = path.size() - 1; i >= 0; i--) {
        printf("%d ", path[i]);
    }
    printf("%d %d\n", d[ed], minCost);
    return 0;

}
/*
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
 */

运行结果
在这里插入图片描述

发布了51 篇原创文章 · 获赞 1 · 访问量 6053

猜你喜欢

转载自blog.csdn.net/qq_39827677/article/details/104460014
今日推荐