1. 程式人生 > >CCF 201712-4 行車路線 (spfa)

CCF 201712-4 行車路線 (spfa)

問題描述

小明和小芳出去鄉村玩,小明負責開車,小芳來導航。

小芳將可能的道路分為大道和小道。大道比較好走,每走 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 號路口是連通的。

輸出格式

輸出一個整數,表示最優路線下小明的疲勞度。

樣例輸入

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

思路

對於同一個點,假設最後一次從大道走過來和從小道走過來的花費是一樣的,顯然大道比較划算,因為它對下一次走小道的消耗沒有貢獻,從而可以保證最優解。

那麼,我們把大道和小道分開計算。

首先通過 Floyd 演算法合併一下所有的小道,然後再通過 spfa 尋找最優解。

每一次的迭代中我們只需要考慮當前狀態的轉移即可:[大道/小道 -> 大道]、[大道 -> 小道]

AC 程式碼

#include<bits/stdc++.h>
#define IO ios::sync_with_stdio(false);\
    cin
.tie(0);\ cout.tie(0); #define inf 0x3f3f3f using namespace std; typedef long long LL; const int maxn = 5e2+10; int n,m; LL G[maxn][maxn]; LL G2[maxn][maxn]; LL dist[maxn]; LL dist2[maxn]; bool vis[maxn]; void floyd() { for(int i=1; i<=n; i++) for(int j=i+1; j<=n; j++) for(int k=1; k<=n; k++) G2[i][j] = min(G2[i][j],G2[i][k]+G2[k][j]); } void init() { memset(dist,inf,sizeof(dist)); memset(dist2,inf,sizeof(dist2)); memset(vis,false,sizeof(vis)); memset(G,inf,sizeof(G)); memset(G2,inf,sizeof(G2)); } void spfa(int st,int ed) { queue<int> sk; dist[st] = dist2[st] = 0; vis[st] = true; sk.push(st); while(!sk.empty()) { int u = sk.front(); sk.pop(); vis[u] = false; for(int i=1; i<=n; i++) { int xlen = min(dist[u],dist2[u]); bool flag = false; if(dist[i] > xlen + G[u][i]) { dist[i] = xlen + G[u][i]; flag = true; } if(G2[u][i]!=4557430888798830399LL) { if(dist2[i] > dist[u] + G2[u][i] * G2[u][i]) { dist2[i] = dist[u] + G2[u][i] * G2[u][i]; flag = true; } } if(flag && !vis[i]) { vis[i] = true; sk.push(i); } } } } int main() { IO; init(); cin>>n>>m; for (int i = 0; i < m ; i++) { LL t,a,b,c; cin>>t>>a>>b>>c; if(t) G2[a][b] = G2[b][a] = min(G2[a][b],c); else G[a][b] = G[b][a] = min(G[a][b],c); } floyd(); spfa(1,n); cout<<min(dist[n],dist2[n])<<endl; return 0; }