題目描述
簡單翻譯一下題目:
給出N個城市,M條無向邊,每個城市都有一定數目的救援小組,所有邊的邊權已知。現在給出起點和終點,求從起點到終點的最短路徑條數及最短路徑上的救援小組數目之和。如果有多條最短路徑,則輸出數目之和最大的。
題目分析
由於我們的起點是固定的,所以本題就是求解出從起點到終點的最短距離,很明顯這是一個單源最短路徑問題,即Dijkstra算法。
但是由於每一個頂點都具有一個權重,對應於題中所說的每個城市有一定數量的搜救隊員。我們需要找到一條最短路徑且可以蒐集到最多搜救隊員的路徑,即這條路徑上經過的點權重和最大。
標準的Dijsktra算法解題,但是我們需要開闢兩個數組分別記錄點權和到達某點的最大點權和。接下來就是本題中最容易忽視的點,題目要求我們找出最短路徑條數而不是最短路徑長度。
我們可以看到從V0到V2,可以有兩條最短路徑:1.V0->V2 2.V0->V1->V2
這兩條最短路徑長度都是2,樣例中的答案也給出的是2,所以這會讓大家產生混淆,以爲題目要求我們輸出的是最短路徑長度。
因此,我們也需要單獨開闢一個數組來記錄最短路徑條數,怎麼更新這個數組中的值呢?
我們假設起點爲s,終點爲v,中介點爲u,如果從s直接到達v的距離 > 從s到u再到v的距離和的話,我們就將最小距離更新,並且用num[u]來更新num[v],這條最短路徑的條數應該是和從s到u的最短路徑條數的相同的。
如果從s直接到達v的距離 = 從s到u再到v的距離和的話,我們就應該將num[v]+=num[u],此時又遇到了相同最短路徑,條數應該+num[u]。
最終我們輸出num[終點]和w[終點] (w是點權數組)。
代碼
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int MAX = 510;//最多結點數
const int INF = 100000000;
int st,ed,n,m;//起點,終點,點數,邊數
int G[MAX][MAX];//鄰接矩陣
int num[MAX];//num[i]記錄到達i點的最短路徑條數
int weight[MAX],w[MAX],d[MAX];//點權,w[i]表示到達點i時的最大點權,d[i]表示從起點到點i的最短距離
bool vis[MAX] = {false};//記錄某個結點是否被訪問過,初始都未訪問過
void Dijkstra(int s)//s爲起點
{
memset(num,0,sizeof(num));
memset(w,0,sizeof(w));
fill(d,d+MAX,INF);
num[s] = 1;
d[s] = 0;
w[s] = weight[s];
for(int j = 0;j < n;j++)
{
int u = -1;//記錄當前距離最近的結點序號
int min = INF;
for(int i = 0;i < n;i++)
{
if(vis[i]==false && d[i] < min)
{
u = i;
min = d[i];
}
}
if(u == -1)
return;
vis[u] = true;
for(int k = 0;k < n;k++)
{
//如果k未被訪問且u可以到達k且以u爲中介點可以使d[k]更優
if(G[u][k]!=INF&&vis[k]==false)
{
if(d[u]+G[u][k]<d[k])
{
d[k] = d[u]+G[u][k];
w[k] = w[u]+weight[k];
num[k] = num[u];
}
else if(G[u][k]+d[u]==d[k])
{
if(weight[k]+w[u] > w[k])//以u爲中介點可以形成更大的點權
w[k] = weight[k]+w[u];
num[k] += num[u];//此時遇到了一條最短長度相等的路徑,要在原有基礎上加上num[u]
}
}
}
}
}
int main()
{
scanf("%d %d %d %d",&n,&m,&st,&ed);//輸入邊數,點數,起點和終點
for(int i = 0;i < n;i++)
{
scanf("%d",&weight[i]);
}
int u,v;//兩個相連的頂點
fill(G[0],G[0]+MAX*MAX,INF);//初始化圖G
for(int i = 0;i < m;i++)
{
scanf("%d %d",&u,&v);
scanf("%d",&G[u][v]);
G[v][u] = G[u][v];
}
Dijkstra(st);
printf("%d %d\n",num[ed],w[ed]);//最短距離條數,最短路徑中的最大點權
return 0;
}
答題用時19min
Q3——finish√