PAT (Advanced Level) Practice 1003 Emergency Dijkstra算法的應用

PAT原題鏈接: 傳送門

1003 Emergency (25 分)

As an emergency rescue team leader of a city, you are given a special map of your country. The map shows several scattered cities connected by some roads. Amount of rescue teams in each city and the length of each road between any pair of cities are marked on the map. When there is an emergency call to you from some other city, your job is to lead your men to the place as quickly as possible, and at the mean time, call up as many hands on the way as possible.

Input Specification:

Each input file contains one test case. For each test case, the first line contains 4 positive integers: N (≤500) - the number of cities (and the cities are numbered from 0 to N?1), M - the number of roads, C1 and C2 - the cities that you are currently in and that you must save, respectively. The next line contains N integers, where the i-th integer is the number of rescue teams in the i-th city. Then M lines follow, each describes a road with three integers c?1, c?2 and L, which are the pair of cities connected by a road and the length of that road, respectively. It is guaranteed that there exists at least one path from C1 to C2.

Output Specification:

For each test case, print in one line two numbers: the number of different shortest paths between C?1 and C?2?? , and the maximum amount of rescue teams you can possibly gather. All the numbers in a line must be separated by exactly one space, and there is no extra space allowed at the end of a line.

Sample Input:

5 6 0 2
1 2 1 5 3
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1

Sample Output:

2 4

題目大意

題目給出n個城市有m條邊使得每兩個城市有一條道路相連估灿,每條邊有著相應的長度,城市編號由0~n-1簿晓,起初每個城市都有一定人數的救援隊帽借,現在給出一個出發(fā)點c1和終點c2晚唇,終點發(fā)生火災后要求你帶領出發(fā)點的救援隊出發(fā)救援,沿途召集你經過的城市的救援隊參與救援,要求路程盡可能的短萤衰,同時如果有多條路一樣短則記錄下這樣的路總數有幾條艰争,同時記錄下這幾條最短的路中你可以沿途召集到的盡可能多的救援隊的數量坏瞄,輸出最短路徑數和最多可召集的救援隊數量

題目分析

典型的求一固定點到其他任意點的最短路徑問題,通過dijkstra算法求從c1出發(fā)到其他點的最短路徑园细,從c1出發(fā)初始化c1到自己的路徑長度為0惦积,其余為無窮大,在dist數組中保存從c1點出發(fā)到其他各點的最短路徑猛频,循環(huán)n-1次狮崩,每次從中選擇一個未走過的最短點,作為下一個要走的點鹿寻,因為已經將c1到達自己的距離設置為0睦柴,所以第一次選擇的dist[c1]的點,代表從c1出發(fā)毡熏,和題意相合(設置man數組放置每個點初始有的救援隊坦敌,num數組放置到達某個點的最短路徑的數量,peo放置到達某個點的最多的救援隊)

在具體選擇出下一個點k之后痢法,遍歷通過該點k是否會使得從c1出發(fā)到達其他點j的最短路徑縮小狱窘,判斷可以走之后,還有兩種可能性:

  • 到j點路徑長度縮小 因為j是通過k到達的财搁,所以到j的走法num[j]=num[k]蘸炸,j的救援隊最多是peo[k]+j點原來的人數
  • 到j點路徑長度不變 那么j可以通過k到達,也可以不通過尖奔,num[j]+=num[k],j的救援隊最多為max(peo[j],peo[k]+man[j]),通過k到j的人多還是通過別的走法到j的人多搭儒,取一個大的值即可

本題代碼

#include<iostream>
#include<algorithm>
#include<string>
#include<cstdio>
#include<queue>
#include<string.h>
#include<cmath>
using namespace std;

const int N=505;
const int M=0x3f3f3f3f;//存放最大值
int vis[N];//是否走過的點
int mat[N][N];//兩點之間的距離
int man[N];//某地初始時救援隊的數量
int dist[N];//從c1出發(fā)到其他地的最短路徑
int num[N];//c1到其他點的最短路徑的條數
int peo[N];//c1到其他點可召集的救援隊數量,在最短路徑的基礎上
int n,m,c1,c2;

int main(){
    scanf("%d%d%d%d",&n,&m,&c1,&c2);
    for(int i=0;i<n;i++) 
        scanf("%d",&man[i]);
    //初始化
    memset(dist,M,sizeof(dist));
    memset(mat,M,sizeof(mat));
    dist[c1]=0;
    mat[c1][c1]=0;
//  memset(vis,0,sizeof(vis));
//  memset(num,0,sizeof(num));
//  memset(peo,0,sizeof(peo));
    num[c1]=1;          //到達起始點的最短路徑初始化為1條
    peo[c1]=man[c1];        //到達起始點的人數最多為man[c1] 
    int a,b,c;
    for(int i=0;i<m;i++){
        scanf("%d%d%d",&a,&b,&c);
        mat[a][b]=c;
        mat[b][a]=c;
    }
//  for(int i=0;i<n;i++)
//      dist[i]=mat[c1][i];
    for(int i=1;i<n;i++){
        int minn=M;
        int k=-1;
        for(int j=0;j<n;j++){
            if(vis[j]==0&&dist[j]<minn){
                minn=dist[j];
                k=j;
            }
        }
        if(k==-1) break;    //剩下的道路已經不通 
        vis[k]=1;
        for(int j=0;j<n;j++){
            if(vis[j]==0&&dist[k]+mat[k][j]<M&&dist[k]+mat[k][j]<dist[j]){
                //有更短的路徑
                dist[j]=dist[k]+mat[k][j];
                num[j]=num[k];
                peo[j]=peo[k]+man[j];
            }
            else if(vis[j]==0&&dist[k]+mat[k][j]<M&&dist[k]+mat[k][j]==dist[j]){    //此處的else if開始用成了if 
                num[j]+=num[k];
                peo[j]=max(peo[j],peo[k]+man[j]);
            }
        } 
    }
    printf("%d %d\n",num[c2],peo[c2]);
    return 0;
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末提茁,一起剝皮案震驚了整個濱河市淹禾,隨后出現的幾起案子,更是在濱河造成了極大的恐慌茴扁,老刑警劉巖铃岔,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異丹弱,居然都是意外死亡德撬,警方通過查閱死者的電腦和手機铲咨,發(fā)現死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蜓洪,“玉大人纤勒,你說我怎么就攤上這事÷√矗” “怎么了摇天?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長恐仑。 經常有香客問我泉坐,道長,這世上最難降的妖魔是什么裳仆? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任腕让,我火速辦了婚禮,結果婚禮上歧斟,老公的妹妹穿的比我還像新娘纯丸。我一直安慰自己,他們只是感情好静袖,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布觉鼻。 她就那樣靜靜地躺著,像睡著了一般队橙。 火紅的嫁衣襯著肌膚如雪坠陈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天捐康,我揣著相機與錄音仇矾,去河邊找鬼。 笑死解总,一個胖子當著我的面吹牛若未,可吹牛的內容都是我干的。 我是一名探鬼主播倾鲫,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼萍嬉!你這毒婦竟也來了乌昔?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤壤追,失蹤者是張志新(化名)和其女友劉穎磕道,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體行冰,經...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡溺蕉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年伶丐,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疯特。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡哗魂,死狀恐怖,靈堂內的尸體忽然破棺而出漓雅,到底是詐尸還是另有隱情录别,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布邻吞,位于F島的核電站组题,受9級特大地震影響,放射性物質發(fā)生泄漏抱冷。R本人自食惡果不足惜崔列,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望旺遮。 院中可真熱鬧赵讯,春花似錦、人聲如沸趣效。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽跷敬。三九已至讯私,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間西傀,已是汗流浹背斤寇。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留拥褂,地道東北人娘锁。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像饺鹃,于是被迫代替她去往敵國和親莫秆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354