CCF 201712-4 行車路線 (spfa)
阿新 • • 發佈:2019-01-03
問題描述
小明和小芳出去鄉村玩,小明負責開車,小芳來導航。
小芳將可能的道路分為大道和小道。大道比較好走,每走 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;
}