GPLT L2-001. 緊急救援【Dijkstra】

題目:緊急救援

思路:

看下問題:

(1)求最短路徑;

(2)記錄不同最短路徑的個數即最短路徑可能存在多條相同的值,但路徑不同;

(3)在最短路徑的基礎上篩選人數最多的一條路徑;

(4)記錄路徑。

求解:

利用最基本的Dijkstra直接可求出問題(1);

而問題(2)和(3)其實同解問題(1)一樣,只需再添加倆個數組,分別記錄到每個點路徑個數和人數即可。

記錄路徑條數:當篩選最短路徑時,只需記錄將當前路徑個數數組等於上一步的路徑個數即可,而當出現相等的路徑時,將上一步的路徑個數累加到當前路徑個數數組。

記錄人數:只需當出現相等的最優解路徑時,進行比較當前的人數後更新最優解人數即可。

而問題(4)就是同鏈表一樣,記錄上一結點即可:只需每次進行選取最優解時用一個數組進行記錄上一步的位置即可,因爲每個點只出現一次,所有記錄路徑時不會出現覆蓋情況。

參考:_TCgogogo_博客

代碼:

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int maxn = 505;
const int inf = 999999999;
int n,g[maxn][maxn],person[maxn];
int dis[maxn],pathNum[maxn],tolpes[maxn],visit[maxn],path[maxn];
void init(){//初始化圖的所有路徑都爲無窮大
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            if(i == j) g[i][j] = 0;else g[i][j]= inf;
}
void Dijkstra(int s){
    for(int i=0;i<n;i++){
        dis[i] = g[s][i];//將s到其他點的路徑值保存到數組中,數組的下標分別代表s到i路徑的距離
        if(dis[i] != inf){//如果當前路徑有路,進行記錄路徑條數和人數
            pathNum[i] = 1;//s到i可通,條數1
            tolpes[i] = person[s] + person[i];//將s到i的人數記錄
        }
    }
    memset(visit,0,sizeof(visit));//標記數組置0
    visit[s] = 1;//標記源點
    for(int i=0;i<n;i++){
        int minn = inf,record;
        for(int j=0;j<n;j++)//尋找s到其他點中路徑最小的那個點作爲下一個走到的點
            if(dis[j] < minn && !visit[j]){minn = dis[j];record = j;}
        visit[record] = 1;//標記當前走到的點
        for(int j=0;j<n;j++){//用當前點到其他點與最優解比較,更新最優解
            if(visit[j]) continue;
            if(g[record][j] + dis[record] < dis[j]){//當前點到j點加上s到當前點的路徑與當前j的最優解進行比較
                dis[j] = dis[record] + g[record][j];//更新最優解路徑
                tolpes[j] = person[j] + tolpes[record];//更新人數
                pathNum[j] = pathNum[record];//因爲沒有達到相同的最優解,所有當前的不同路徑條數還是上一步的條數
                path[j] =record;//記錄路徑,每次記錄上一節點
            }
            else if(g[record][j] + dis[record] == dis[j] && record != j){//當最優解相等時說明要更新條數和人數了
                pathNum[j]+=pathNum[record];//將上一步的條數都累加到本次!
                if(person[j] + tolpes[record] > tolpes[j]){//篩選人數最優解
                    tolpes[j] = person[j] + tolpes[record];
                    path[j] = record;//記錄路徑
                }
            }
        }
    }
}
int main()
{
    int m,s,d,u,v,l;
    while(~scanf("%d%d%d%d",&n,&m,&s,&d)){
        init();
        for(int i=0;i<n;i++) scanf("%d",&person[i]);
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&u,&v,&l);
            g[u][v] = g[v][u] = l;
        }
        Dijkstra(s);
        int prtPath[maxn],cnt = 0;
        printf("%d %d\n",pathNum[d],tolpes[d]);
        //將路徑找出來
        prtPath[cnt++] = d;
        while(path[d] != s){
            d = path[d];
            prtPath[cnt++] = d;
        }
        prtPath[cnt++] = s;
        while(--cnt) printf("%d ",prtPath[cnt]);printf("%d\n",prtPath[cnt]);
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章