1. 程式人生 > >PAT 資料結構 06-圖5. 旅遊規劃dijkstra演算法

PAT 資料結構 06-圖5. 旅遊規劃dijkstra演算法

題意:

有了一張自駕旅遊路線圖,你會知道城市間的高速公路長度、以及該公路要收取的過路費。現在需要你寫一個程式,幫助前來諮詢的遊客找一條出發地和目的地之間的最短路徑。如果有若干條路徑都是最短的,那麼需要輸出最便宜的一條路徑。

輸入:

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

輸出:

3 40

題解:

#include<bits/stdc++.h>
using namespace std;
#define MAXN 505
#define INFINITY 505
struct City
{
    int len;
    int fees;
};
int N;  //城市的個數 編號 0 ~ (N - 1)
int M;  //高速公路的條數
int S;  //出發地的城市編號
int D;  //目的城市編號
City city[MAXN][MAXN];  //圖
int flag[MAXN]; //標記
City dist[MAXN];   //dist表示 這個點到原點的最短路徑
int Length;    //路徑長度
int Fees;  //收費額

void init()
{
    for(int i = 0; i < N; ++i)
    {
        for(int j = 0; j < N; ++j)
        {
            city[i][j].len = INFINITY;
            city[i][j].fees = INFINITY;
        }
    }
    for(int i = 0; i < N; ++i)
    {
        dist[i].len = INFINITY;
        dist[i].fees = INFINITY;
    }
}

void setDistValue(int s, int i, int j)
{
    dist[S].len = i;
    dist[S].fees = j;
}

int findMinDist()
{
    City minDist;
    minDist.fees = INFINITY;
    minDist.len = INFINITY;

    int V;  //用於返回的頂點

    for(int i = 0; i < N; ++i)
    {
        if(flag[i] == 0)
        {//找到與之最短距離的點;
            if(dist[i].len < minDist.len)
            {
                minDist.len = dist[i].len;
                minDist.fees = dist[i].fees;
                V = i;
            }
            else if(dist[i].len == minDist.len)
            {
                if(dist[i].fees < minDist.fees)
                    minDist.fees = dist[i].fees;
            }
        }
    }
    if(minDist.len < INFINITY)
        return V;       //返回對應的頂點下標
    else    return -1;  //這樣的頂點不存在,返回錯誤標記
}

void dijkstra()
{
    setDistValue(S, 0, 0);  //將起點S吃入集合
    flag[S] = 1;            //標記
    for(int i = 0 ; i < N; ++i)
    {
        dist[i].len = city[S][i].len;
        dist[i].fees = city[S][i].fees;
    }//初始化;
    int V;                  //用來表示頂點下標
    while(1)
    {
        V = findMinDist();//仔細理解一下這個點;
        if(V == -1)     //這樣結點不存在
            break;
        flag[V] = 1;    //吃入
        for(int i = 0; i < N; ++i)  //對圖中的每個頂點
        {
            if(flag[i] == 0 && city[V][i].len < INFINITY)   // W是V的鄰邊且未被吃入
            {
                if(city[V][i].len < 0) //為負邊
                    return ;    //不能正確處理,返回錯誤標記
                if(dist[V].len + city[V][i].len < dist[i].len)  //吃入V使得dist[i]變小
                {
                    dist[i].len = dist[V].len + city[V][i].len;
                    dist[i].fees = dist[V].fees + city[V][i].fees;
                }
                else if(dist[V].len + city[V][i].len == dist[i].len)   //吃入V等於dist[i]
                {
                    if(dist[V].fees + city[V][i].fees < dist[i].fees)   //路費比其少則更新
                        dist[i].fees = dist[V].fees + city[V][i].fees;
                }

            }
        }
    }
}

int main()
{
    scanf("%d%d%d%d", &N, &M, &S, &D);
    init(); //初始化
    int beginCity;
    int endCity;
    int len;
    int fees;
    for(int i = 0; i < M; ++i)
    {
        scanf("%d%d%d%d", &beginCity, &endCity, &len, &fees);
        city[beginCity][endCity].len = len;
        city[beginCity][endCity].fees = fees;
        city[endCity][beginCity].len = len;
        city[endCity][beginCity].fees = fees;
        //路是雙向的;
    }
    dijkstra();
    printf("%d %d", dist[D].len, dist[D].fees);

    return 0;
}