【PAT A1030】旅行プラン

【PAT A1030】旅行プラン

旅行者のマップは一緒に、各高速道路のコストで、高速道路に沿って都市間の距離を提供します。今、あなたは彼/彼女の開始都市と目的地間の最短経路を決定するために旅行者を支援するプログラムを書くことになっています。そのような最短経路が一意でない場合、あなたは一意であることが保証される最小のコスト、と一つの出力になっています。
入力仕様:
各入力ファイルは、1つのテストケースが含まれています。各ケースが4つの正の整数N、M、S、及びN(≤500)は都市の数である(したがって、都市が0からN-1までの番号が付けられている)Dを含む行から始まります。Mは、高速道路の数です。S及びDは、それぞれ、開始および宛先の都市です。次いで、M行の形式で、各高速道路の情報を提供し、次のとおりです。
CITY1 City2この距離原価
番号はこれ以上の500以上のすべての整数であり、スペースで区切られます。
出力仕様:
各テストケースについては、先に出発点からの最短経路に沿って一列に印刷する都市は、総距離及び経路の総コストが続きます。数字はスペースで区切る必要があり、出力の末尾に余分なスペースがあってはなりません。
サンプル入力:
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 1 20
サンプル出力:
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