1. 程式人生 > >資料結構—— 城市間緊急救援

資料結構—— 城市間緊急救援

7-1 城市間緊急救援 (25 分)

作為一個城市的應急救援隊伍的負責人,你有一張特殊的全國地圖。在地圖上顯示有多個分散的城市和一些連線城市的快速道路。每個城市的救援隊數量和每一條連線兩個城市的快速道路長度都標在地圖上。當其他城市有緊急求助電話給你的時候,你的任務是帶領你的救援隊儘快趕往事發地,同時,一路上召集儘可能多的救援隊。

輸入格式:

輸入第一行給出4個正整數N、M、S、D,其中N(2≤N≤500)是城市的個數,順便假設城市的編號為0 ~ (N−1);M是快速道路的條數;S是出發地的城市編號;D是目的地的城市編號。

第二行給出N個正整數,其中第i個數是第i個城市的救援隊的數目,數字間以空格分隔。隨後的M行中,每行給出一條快速道路的資訊,分別是:城市1、城市2、快速道路的長度,中間用空格分開,數字均為整數且不超過500。輸入保證救援可行且最優解唯一。

輸出格式:

第一行輸出最短路徑的條數和能夠召集的最多的救援隊數量。第二行輸出從S到D的路徑中經過的城市編號。數字間以空格分隔,輸出結尾不能有多餘空格。

輸入樣例:

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

輸出樣例:

2 60
0 1 3

 一道典型的最短路徑問題,首先想到使用迪傑斯特拉演算法,進行最短路i經的求解,迪傑斯特拉演算法詳解

但是當我們深入分析時卻發現,自己沒有辦法統計最短路徑的條數和能夠召集的最多的救援隊數量,我們只能統計最短路徑的邊權值。

在翻部落格的時候看到了大佬說的一句話:一切演算法皆思想

,掌握了演算法思想就掌握了這一類所有演算法,然後再看大佬的程式碼,真的是將思想掌握的很透徹,和板子完全不同,但又思想一致,功能相同,在此ORZ一波,希望自己也能達到那種水平。

言歸正傳,在進行演算法時,我們是不統計如果長度相同時的情況的,但是最短路徑的條數和能夠召集的最多的救援隊數量的求取都都要求我們對這類情況進行討論,能夠召集的最多的救援隊數量就可以在這裡進行求解。

有人可能會這麼想最短路徑的條數是不是隻要最短路徑相等,而且到達的點為終點,就設立一個變數使它+1呢?

首先這個是錯誤的,因為每個點都有多條路徑到達,而到達最終定點的路徑的個數等於各個點的路徑的乘積,這是我們需要特別注意的地方,那麼剩下的就是程式碼實現了。

下面給出AC程式碼:

#include <bits/stdc++.h>

using namespace std;
const int maxn=500+10;
const int INF=0x3f3f3f3f;
int V,E,s,t,num=0;
int cost[maxn][maxn];
int d[maxn];
int prev1[maxn];
int value[maxn];
int roadnum[maxn];
int amount[maxn];
bool used[maxn];



void dijkstra(int s)
{
    memset(d,INF,sizeof(d));
    memset(used,false,sizeof(used));
    memset(prev1,-1,sizeof(prev1));
    memset(roadnum,0,sizeof(roadnum));
    memset(amount,0,sizeof(amount));
    d[s]=0;
    roadnum[s]=1;
    amount[s]=value[s];

    while(true)
    {
        int v=-1;
        for(int u=0;u<V;u++)
        {
            if(!used[u]&&(v==-1||d[u]<d[v])) v=u;
        }

        if(v==-1) break;
        used[v]=true;

        for(int u=0;u<V;u++)
        {

            if(d[u]>d[v]+cost[v][u])
            {
                d[u]=d[v]+cost[v][u];
                amount[u]=amount[v]+value[u];
                roadnum[u]=roadnum[v];
                prev1[u]=v;
                //cout<<"gg1:     "<<amount[u]<<"    "<<u<<"    "<<v<<endl;
            }
            else if(d[u]==d[v]+cost[v][u])
            {
                roadnum[u]+=roadnum[v];
                if(amount[u]<amount[v]+value[u])
                {
                    amount[u]=amount[v]+value[u];
                    prev1[u]=v;
                    //cout<<"gg2:     "<<amount[u]<<"    "<<u<<"    "<<v<<endl;

                }

            }

        }
    }
}


int main()
{
    scanf("%d %d %d %d",&V,&E,&s,&t);
    for(int i=0;i<V;i++) memset(cost[i],INF,sizeof(cost[i]));

    for(int i=0;i<V;i++) scanf("%d",&value[i]);
    for(int i=0;i<E;i++)
    {
        int a,b,c; scanf("%d %d %d",&a,&b,&c);
        cost[a][b]=cost[b][a]=c;
    }
    dijkstra(s);

    int prevt[maxn];
    int pos=0;

    int tt=t;
    for(;tt!=-1;tt=prev1[tt])
    {
        prevt[pos++]=tt;
    }

    printf("%d %d\n",roadnum[t],amount[t]);
    for(int i=pos-1;i>=0;i--)
    {
        if(i) printf("%d ",prevt[i]);
        else printf("%d",prevt[i]);
    }

    return 0;
}