題目:緊急救援
思路:
看下問題:
(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;
}