題目連接
https://pta.patest.cn/pta/test/15/exam/4/question/862
5-35 城市間緊急救援 (25分)
作為一個城市的應急救援隊伍的負責人,你有一張特殊的全國地圖。在地圖上顯示有多個分散的城市和一些連接城市的快速道路。每個城市的救援隊數量和每一條連接兩個城市的快速道路長度都標在地圖上。當其他城市有緊急求助電話給你的時候,你的任務是帶領你的救援隊盡快趕往事發地,同時,一路上召集盡可能多的救援隊。
輸入格式:
輸入第一行給出4個正整數NN、MM、SS、DD,其中NN(2\le N\le 5002≤N≤500)是城市的個數,順便假設城市的編號為0 ~ (N-1)(N−1);MM是快速道路的條數;SS是出發地的城市編號;DD是目的地的城市編號。
第二行給出NN個正整數,其中第ii個數是第ii個城市的救援隊的數目,數字間以空格分隔。隨后的MM行中,每行給出一條快速道路的信息,分別是:城市1、城市2、快速道路的長度,中間用空格分開,數字均為整數且不超過500。輸入保證救援可行且最優解唯一。
輸出格式:
第一行輸出最短路徑的條數和能夠召集的最多的救援隊數量。第二行輸出從SS到DD的路徑中經過的城市編號。數字間以空格分隔,輸出結尾不能有多余空格。
輸入樣例:
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
分析:
這個問題首先是一個最短路的算法,這個載體還是比較簡單的,但是,它的難點就在於它的相關附加內容。
路徑就用一個path數組記錄,然后用一個遞歸調用就可以了。
救援隊的數量也是用一個數組來存放。
這個問題的關鍵是最短路徑的條數,這個問題我先是用一個全局變量來存放,可是后來發現這樣不行,因為可能有幾種不同的到達方式。
所以就用了一個數組,又前往后的推理分析,從而得出最后的結論。
但這道題確實好,坑也確實挺多,首先就是if else的分析,我以前不太喜歡用else這次就被坑慘了。。
還有就是這個題,為了防止一些不必要的訪問,對我原有的問題進行干擾,我設置了兩個標記數組。vis主要是為了最短路而設計的,而另一個visited數組,主要是為了防止有一樣的距離時,對我原有的好的結果造成干擾。
代碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define infinity 100000
int arc[520][520]; // array for the picture
int dist[520]; //distance from the start city
int emer[520]; // emergency team at every city
int vis[520]; // mark array
int visited[520]; // another mark array
int path[520];
int rever_path[520];
int total_team[520]; // this node 's emergency team
int ans[520];
int main()
{
memset(ans,0,sizeof(ans));
int n,m,s,d; // n:the num of the city ; m:the num of the road; s:start city ; d:destination city;
//freopen("1.txt","r+",stdin);
scanf("%d%d%d%d",&n,&m,&s,&d);
for(int i=0; i<n; i++)
scanf("%d",&emer[i]);
for(int i=0; i<n; i++)
{
for(int j=0; j<n; j++)
arc[i][j]=arc[j][i]=infinity;
}
for(int i=0; i<m; i++)
{
int start,next,distance;
scanf("%d%d%d",&start,&next,&distance);
arc[start][next]=arc[next][start]=distance;
}
if(s==d)
{
printf("1 %d\n",emer[s]);
printf("%d\n",s);
}
else{
for(int i=0; i<n; i++)
{
dist[i]=infinity;
if(arc[s][i]!=infinity)
{
dist[i]=arc[s][i];
ans[i]++;
}
}
for(int i=0; i<n; i++)
total_team[i]=emer[s];
memset(vis,0,sizeof(vis));
memset(visited,0,sizeof(visited));
dist[s]=0;
vis[s]=1;
int total_mindist=1;
for(int j=1; j<n; j++)
{
//printf("%d@\n",ans[3]);
int min_distance=infinity,min_position=s;
for(int i=0; i<n; i++)
{
if(!vis[i])
if(dist[i]<min_distance)
{
min_distance=dist[i];
min_position=i;
}
}
//ans[min_position]++;
vis[min_position]=1;
if(!visited[min_position]){
path[min_position]=s;
total_team[min_position]+=emer[min_position];
}
// printf("%d\n",min_position);
for(int i=0; i<n; i++)
{
if(!vis[i])
{
if(min_distance+arc[min_position][i]<dist[i])
{
ans[i]=ans[min_position];
//printf("%d11\n",ans[3]);
total_mindist=1;
dist[i]=min_distance+arc[min_position][i];
path[i]=min_position;
total_team[i]=total_team[min_position]+emer[i];
//printf("%d!*\n",total_team[3]);
visited[i]=1;
}
else if(min_distance+arc[min_position][i]==dist[i]) // else 防止上一個if語句對這個if造成的影響
{
ans[i]+=ans[min_position]; // 原來的路徑數加上新增的路徑數
if(total_team[min_position]+emer[i]>total_team[i])
{
total_mindist++;
total_team[i]=total_team[min_position]+emer[i];
path[i]=min_position;
//printf("%d\n",path[i]);
//printf("%d!\n",total_team[3]);
visited[i]=1;
}
}
}
// printf("%d!0%d\n",total_team[3],ans[3]);
}
}
int num=d,path_num=0;
//printf("%d0\n",path[3]);
while(num!=s)
{
//printf("%d\n",num);
//printf("#%d\n",path[num]);
rever_path[path_num]=num;
path_num++;
num=path[num];
//printf("%d\n",num);
}
rever_path[path_num]=s;
printf("%d %d\n",ans[d],total_team[d]);
num=d;
for(int i=path_num; i>0; i--)
printf("%d ",rever_path[i]);
printf("%d\n",d);
}
return 0;
}
