Problem Description
雖然草兒是個路癡(就是在杭電待了一年多,居然還會在校園裡迷路的人,汗~),但是草兒仍然很喜歡旅行,因為在旅途中 會遇見很多人(白馬王子,^0^),很多事,還能豐富自己的閱歷,還可以看美麗的風景……草兒想去很多地方,她想要去東京鐵塔看夜景,去威尼斯看電影,去陽明山上看海芋,去紐約純粹看雪景,去巴黎喝咖啡寫信,去北京探望孟姜女……眼看寒假就快到了,這麼一大段時間,可不能浪費啊,一定要給自己好好的放個假,可是也不能荒廢了訓練啊,所以草兒決定在要在最短的時間去一個自己想去的地方!因為草兒的家在一個小鎮上,沒有火車經過,所以她只能去鄰近的城市坐火車(好可憐啊~)。
Input
輸入數據有多組,每組的第一行是三個整數T,S和D,表示有T條路,和草兒家相鄰的城市的有S個,草兒想去的地方有D個;
接著有T行,每行有三個整數a,b,time,表示a,b城市之間的車程是time小時;(1=<(a,b)<=1000;a,b 之間可能有多條路)
接著的第T+1行有S個數,表示和草兒家相連的城市;
接著的第T+2行有D個數,表示草兒想去地方。
Output
輸出草兒能去某個喜歡的城市的最短時間。
如題 , 此題是一道明顯的最短路問題,可以用dijkstra 和 spfa 等解決 。一般的做法很容易想到,就是求出所有出發的站 到所有 終點站的 最短路徑中的最小值 ,這樣就重復多次調用dijkstra 或 spfa , 但如果運用一些技巧就可大大優化 , 題目中a , b 均是大於1的,所以可以在設一個點作為草兒的家的位置且該點的序號為 0 , 只要把該點與所有始發站之間均建立一條邊且距離為0 ,那麼只要以點0 為源點 調用一次dijkstra 或 spfa 就可以了。我用的是spfa ,哎,這道題WA了無數次,就是找不到錯在哪裡,最後突然間想到,可能有的目的地是孤立的點(在這裡指草兒無法到達的點 , 即前面未出現過的點)。請看代碼:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<queue> #include<cmath> #include<map> using namespace std ; const int MAXN = 1005 ; const int INF = 0x7fffffff ; int vis[MAXN] ; // 標記數組,確認城市是否出現過 struct Node { int adj ; int dist ; Node * next ; } ; Node * vert[MAXN] ; queue <int> q ; int m , st , dt ; int dest[MAXN] ; int ss[MAXN] ; // 記錄出發站的城市數目 int dd[MAXN] ; // 記錄終點站的城市數目 int dis[MAXN] ; int inq[MAXN] ; int sumc ; // 記錄出現的不同的城市數目 void spfa(int v0) { Node * p ; int i ; for(i = 0 ; i <= sumc ; i ++) { dis[dest[i]] = INF ; } dis[0] = 0 ; while (!q.empty()) { q.pop() ; } q.push(v0) ; inq[v0] ++ ; while (!q.empty()) { int tmp = q.front() ; q.pop() ; inq[tmp] -- ; p = vert[tmp] ; while (p != NULL) { int td = p -> dist ; int tadj = p -> adj ; if(td + dis[tmp] < dis[tadj]) { dis[tadj] = td + dis[tmp] ; if(inq[tadj] == 0) { inq[tadj] ++ ; q.push(tadj) ; } } p = p -> next ; } } } void dele() // 刪除鄰接表 { Node * p ; int i ; for(i = 0 ; i <= sumc ; i ++) { if(i == 0) p = vert[0] ; else p = vert[dest[i]] ; while (p != NULL) { vert[dest[i]] = p -> next ; delete p ; p = vert[dest[i]] ; } } } int main() { while (scanf("%d%d%d" , &m , &st , &dt) != EOF) { memset(vis , 0 , sizeof(vis)) ; memset(vert , 0 , sizeof(vert)) ; memset(dest , 0 , sizeof(dest)) ; memset(dis , 0 , sizeof(dis)) ; memset(inq , 0 , sizeof(inq)) ; int i ; sumc = 0 ; Node * p ; for(i = 0 ; i < m ; i ++) { int a , b , w ; cin >> a >> b >> w ; if(!vis[a]) { vis[a] = 1 ; sumc ++ ; dest[sumc] = a ; } if(!vis[b]) { vis[b] = 1 ; sumc ++ ; dest[sumc] = b ; } p = new Node ; p -> adj = b ; p -> dist = w ; p -> next = vert[a] ; vert[a] = p ; p = new Node ; p -> adj = a ; p -> dist = w ; p -> next = vert[b] ; vert[b] = p ; } for( i = 0 ; i < st ; i ++) { scanf("%d" , & ss[i]) ; if(!vis[ss[i]]) // 這裡也不要忘記判斷 { vis[ss[i]] = 1 ; sumc ++ ; dest[sumc] = ss[i] ; } p = new Node ; p -> adj = ss[i] ; p -> dist = 0 ; p -> next = vert[0] ; vert[0] = p ; p = new Node ; p -> adj = 0 ; p -> dist = 0 ; p -> next = vert[ss[i]] ; vert[ss[i]] = p ; } for( i = 0 ; i < dt ; i ++) { scanf("%d" , & dd[i]) ; if(!vis[dd[i]]) // 這裡也不要忘記判斷,終點站的城市可能第一次出現 { vis[dd[i]] = 1 ; sumc ++ ; dest[sumc] = dd[i] ; } } spfa(0) ; int min = INF ; for( i = 0 ; i < dt ; i ++) { if(min > dis[dd[i]]) { min = dis[dd[i]] ; } } printf("%d\n" , min) ; dele() ; } return 0 ; }