問題描述
小明和小芳出去鄉村玩,小明負責開車,小芳來導航。
小芳將可能的道路分為大道和小道。大道比較好走,每走1公里小明會增加1的疲勞度。小道不好走,如果連續走小道,小明的疲勞值會快速增加,連續走 s公里小明會增加 s 2的疲勞度。
例如:有5個路口,1號路口到2號路口為小道,2號路口到3號路口為小道,3號路口到4號路口為大道,4號路口到5號路口為小道,相鄰路口之間的距離都是2公里。如果小明從1號路口到5號路口,則總疲勞值為(2+2) 2+2+2 2=16+2+4=22。
現在小芳拿到了地圖,請幫助她規划一個開車的路線,使得按這個路線開車小明的疲勞度最小。
小芳將可能的道路分為大道和小道。大道比較好走,每走1公里小明會增加1的疲勞度。小道不好走,如果連續走小道,小明的疲勞值會快速增加,連續走 s公里小明會增加 s 2的疲勞度。
例如:有5個路口,1號路口到2號路口為小道,2號路口到3號路口為小道,3號路口到4號路口為大道,4號路口到5號路口為小道,相鄰路口之間的距離都是2公里。如果小明從1號路口到5號路口,則總疲勞值為(2+2) 2+2+2 2=16+2+4=22。
現在小芳拿到了地圖,請幫助她規划一個開車的路線,使得按這個路線開車小明的疲勞度最小。
輸入格式
輸入的第一行包含兩個整數
n,
m,分別表示路口的數量和道路的數量。路口由1至
n編號,小明需要開車從1號路口到
n號路口。
接下來 m行描述道路,每行包含四個整數 t, a, b, c,表示一條類型為 t,連接 a與 b兩個路口,長度為 c公里的雙向道路。其中 t為0表示大道, t為1表示小道。保證1號路口和 n號路口是連通的。
接下來 m行描述道路,每行包含四個整數 t, a, b, c,表示一條類型為 t,連接 a與 b兩個路口,長度為 c公里的雙向道路。其中 t為0表示大道, t為1表示小道。保證1號路口和 n號路口是連通的。
輸出格式
輸出一個整數,表示最優路線下小明的疲勞度。
樣例輸入
6 7
1 1 2 3
1 2 3 2
0 1 3 30
0 3 4 20
0 4 5 30
1 3 5 6
1 5 6 1
1 1 2 3
1 2 3 2
0 1 3 30
0 3 4 20
0 4 5 30
1 3 5 6
1 5 6 1
樣例輸出
76
樣例說明
從1走小道到2,再走小道到3,疲勞度為5
2=25;然后從3走大道經過4到達5,疲勞度為20+30=50;最后從5走小道到6,疲勞度為1。總共為76。
數據規模和約定
對於30%的評測用例,1 ≤
n ≤ 8,1 ≤
m ≤ 10;
對於另外20%的評測用例,不存在小道;
對於另外20%的評測用例,所有的小道不相交;
對於所有評測用例,1 ≤ n ≤ 500,1 ≤ m ≤ 10 5,1 ≤ a, b ≤ n, t是0或1, c ≤ 10 5。保證答案不超過10 6。
對於另外20%的評測用例,不存在小道;
對於另外20%的評測用例,所有的小道不相交;
對於所有評測用例,1 ≤ n ≤ 500,1 ≤ m ≤ 10 5,1 ≤ a, b ≤ n, t是0或1, c ≤ 10 5。保證答案不超過10 6。
分析
用Dijkstra算法求最短路徑問題。但是題目中多的一個條件是分為大路和小路兩種,所以用兩個數組sr[],br[]存儲從v0到vi的當前最短路徑,意思是如果當前這條路是小路,就將結果存在sr[]中,如果是大路就存在br[]中。
按課本上的Dijkstra算法修改一下使用。
1 #include <iostream> 2 #include <iomanip> 3 #include <sstream> 4 #include <cstdio> 5 #include <string.h> 6 #include <cstring> 7 #include <algorithm> 8 #include <cmath> 9 #include <string> 10 #include <queue> 11 #include <map> 12 #include <vector> 13 #include <set> 14 #include <list> 15 using namespace std; 16 typedef long long ll; 17 const int INF = 0x3f3f3f3f; 18 const int NINF = 0xc0c0c0c0; 19 const int maxn = 505; 20 int MonthDay[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 21 ll big[maxn][maxn], small[maxn][maxn]; 22 int vis_big[maxn], vis_small[maxn]; 23 ll sr[maxn], br[maxn]; 24 ll path[maxn];//記錄頂點v之前正在連續的小路 25 ll n, m; 26 ll Dijkstra(ll v0) 27 { 28 for(ll i = 0; i < n; i++) { 29 sr[i] = small[v0][i]; 30 br[i] = big[v0][i]; 31 if(sr[i] < INF) { 32 path[i] = sr[i]; 33 sr[i] *= sr[i]; 34 } 35 else path[i] = INF; 36 } 37 vis_small[v0] = vis_big[v0] = 1; 38 while(1){ 39 ll minn = INF, flag = 0, v = -1; 40 for(ll j = 0; j < n; j++) { 41 if(!vis_big[j] && br[j] < minn) { 42 flag = 0; 43 v = j; 44 minn = br[j]; 45 } 46 if(!vis_small[j] && sr[j] < minn) { 47 flag = 1; 48 v = j; 49 minn = sr[j]; 50 } 51 } 52 if(v == -1) break; 53 if(flag) vis_small[v] = 1; 54 else vis_big[v] = 1; 55 for(ll j = 0; j < n; j++) { 56 if(!vis_small[j] && small[v][j] < INF) { 57 if(flag) {//prev到v之間是small road 58 ll temp = sr[v] - path[v]*path[v] + (path[v]+small[v][j])*(path[v]+small[v][j]); 59 if(sr[j] > temp || sr[j] == temp && path[j] > path[v]+small[v][j]) { 60 sr[j] = temp; 61 path[j] = path[v]+small[v][j]; 62 } 63 } 64 else{//prev到v之間是big road 65 ll temp = br[v]+small[v][j]*small[v][j]; 66 if(sr[j] > temp || sr[j] == temp && path[j] > small[v][j]) { 67 sr[j] = temp; 68 path[j] = small[v][j]; 69 } 70 } 71 } 72 if(!vis_big[j] && big[v][j] < INF) { 73 if(flag) { 74 ll temp = sr[v] + big[v][j]; 75 br[j] = min(temp, br[j]); 76 } 77 else { 78 ll temp = br[v] + big[v][j]; 79 br[j] = min(temp, br[j]); 80 } 81 } 82 } 83 } 84 return min(br[n-1], sr[n-1]); 85 } 86 int main() { 87 88 ll t, a, b, c; 89 while(cin >> n >> m) { 90 for (ll i = 0; i < n; i++) { 91 for (ll j = 0; j <= i; j++) { 92 big[i][j] = big[j][i] = INF; 93 small[i][j] = small[j][i] = INF; 94 } 95 } 96 memset(vis_big, 0, sizeof(vis_big)); 97 memset(vis_small, 0, sizeof(vis_small)); 98 for (int i = 0; i < m; i++) { 99 cin >> t >> a >> b >> c; 100 a--; 101 b--; 102 if (t == 1) small[a][b] = small[b][a] = min(c, small[a][b]); 103 else big[a][b] = big[b][a] = min(c, big[a][b]); 104 } 105 cout << Dijkstra(0) << endl; 106 } 107 return 0; 108 }