171204 行車路線 ccf

參考c++

http://www.pianshen.com/article/5980255339/算法

(參考網站的代碼註釋中「大路加小路」與「小路加大路」反了,網站中對spfa算法的描述頗有參考價值)ide

思路網站

spfa+大路小路分開處理spa

實現code

經過Floyd算法得出純小路的點間最短路徑,經過dis[wide][i]存儲最後一條路爲大路時源點到i的最短路徑,dis[narrow][i]存儲最後一條路爲小路時源點到i的最短路徑,這樣spfa要考慮「大路加大路」「小路加大路」「大路加小路」三種狀況。blog

  1 #include<bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 #define MAXN 505
  6 
  7 typedef long long ll;
  8 
  9 int n,m;
 10 ll G[2][MAXN][MAXN];
 11 ll dis[2][MAXN];
 12 bool inque[MAXN];
 13 queue<int> q;
 14 
 15 const ll inf=1e18;
 16 const int wide=0;
 17 const int narrow=1;
 18 
 19 int spfa(int start,int n){
 20     //初始化 
 21     for(int i=1;i<=n;i++){
 22         dis[0][i]=dis[1][i]=inf;
 23         inque[i]=false;
 24     }
 25     //start入隊 
 26     q.push(start);
 27     inque[start]=true;
 28     dis[wide][start]=dis[narrow][start]=0;
 29     //spfa計算最短路徑
 30     int u; 
 31     ll v;
 32     while(!q.empty()){
 33         //出隊 
 34         u=q.front();
 35         q.pop();
 36         inque[u]=false;
 37         
 38         for(int i=1;i<=n;i++){
 39             v=G[wide][u][i];
 40             //大路加大路
 41             if(dis[wide][i]>dis[wide][u]+v){
 42                 dis[wide][i]=dis[wide][u]+v;
 43                 if(!inque[i]){
 44                     q.push(i);
 45                     inque[i]=true;
 46                 }
 47             }
 48             //小路加大路
 49             if(dis[wide][i]>dis[narrow][u]+v){
 50                 dis[wide][i]=dis[narrow][u]+v;
 51                 if(!inque[i]){
 52                     q.push(i);
 53                     inque[i]=true;
 54                 }
 55             }
 56             //大路加小路 
 57             v=G[narrow][u][i];
 58             if(v!=inf&&dis[narrow][i]>dis[wide][u]+v*v){
 59                 dis[narrow][i]=dis[wide][u]+v*v;
 60                 if(!inque[i]){
 61                     q.push(i);
 62                     inque[i]=true;
 63                 }
 64             }
 65         }     
 66     }
 67     return min(dis[wide][n],dis[narrow][n]);
 68 }
 69 
 70 int main(){
 71     cin>>n;
 72     cin>>m;
 73     //初始化 
 74     for(int i=1;i<=n;i++){
 75         for(int j=1;j<=n;j++){
 76             G[0][i][j]=G[1][i][j]=inf;
 77         }
 78     }
 79     //輸入邊
 80     int type,u,v,w;
 81     for(int i=0;i<m;i++){
 82         cin>>type>>u>>v>>w;
 83         if(G[type][u][v]>w){                    //注意有重邊的狀況 
 84             G[type][u][v]=G[type][v][u]=w;        
 85         }
 86     } 
 87     //Floyd算法獲得小邊連小邊的狀況
 88     for(int i=1;i<=n;i++){
 89         for(int j=i+1;j<=n;j++){
 90             for(int k=1;k<=n;k++){
 91                 if(k==i||k==j){
 92                     continue;
 93                 }
 94                 if(G[narrow][i][j]>G[narrow][i][k]+G[narrow][k][j]){
 95                     G[narrow][i][j]=G[narrow][j][i]=G[narrow][i][k]+G[narrow][k][j];
 96                 }
 97             }
 98         }
 99     } 
100     
101     cout<<spfa(1,n);
102     
103     return 0;
104 }
View Code

注意ci

有重複邊輸入的狀況,中間結果大小可能超過intget

題目it

問題描述
  小明和小芳出去鄉村玩,小明負責開車,小芳來導航。
  小芳將可能的道路分爲大道和小道。大道比較好走,每走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。
  如今小芳拿到了地圖,請幫助她規劃一個開車的路線,使得按這個路線開車小明的疲勞度最小。
 
輸入格式
  輸入的第一行包含兩個整數 nm,分別表示路口的數量和道路的數量。路口由1至 n編號,小明須要開車從1號路口到 n號路口。
  接下來 m行描述道路,每行包含四個整數 tabc,表示一條類型爲 t,鏈接 ab兩個路口,長度爲 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
 
樣例輸出
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 ≤  ab ≤  nt是0或1, c  ≤ 10 5。保證答案不超過10 6
相關文章
相關標籤/搜索