1. 程式人生 > 實用技巧 >CCFCSP 2017-12-4 行車路線

CCFCSP 2017-12-4 行車路線

最近在幫忙搭建學校CG平臺的CSP題庫,這道題是我的任務之一。讀完題後有了一些思路,又看了看網上的題解,感覺基本一致。

思路:本題求1到n的單源最短路,和最普通的單源最短路的區別是:路分為大道和小道兩種。我們可以將到達每個節點的最短路分成兩部分,一部分是到達該點的上一條路是大路的最短路,另一部分是到達該店的上一條路是小路的最短路,這樣我們就解決了路種類不同的問題,該題也就轉化為了一個簡單的最短路問題。

但是我在看題解程式碼的時發現,好幾個題解的程式碼有問題,我下面這組HACK資料都過不了。

3 3
1 1 2 4
0 1 2 20
1 2 3 20



420

這些程式碼的普遍問題是,沒有將一個節點的最短路分為兩部分,而是另外開了別的陣列去記錄走小路時對最短路的影響。就看上面這組HACK資料,1到2的最短路為16(走1到2的小道),1到3的最短路為420(先走1到2的大道,再走2到3的小道),如果不將節點分開,到達2的最短路只能被更新為16,而上一條路徑的狀態只能是走小路,這保證了達到2是最優的,但是不能保證到達3是最優的。

HDU-6805與這題類似,其關鍵點都是消除限制條件對跑最短路的影響,將題目轉換為一個簡單的最短路問題。

#include<bits/stdc++.h>
#define ri register int
#define ll long long
#define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
const int maxn = 505;
struct edge{
    int v, nxt, type;
    ll w;
}E[200005];
int head[maxn], cnt = 0
; ll dis[maxn][2]; int vis[maxn][2]; int n, m; inline void add(int u, int v, ll w, int t){ E[++cnt].v = v; E[cnt].w = w; E[cnt].nxt = head[u]; E[cnt].type = t; head[u] = cnt; }//鄰接表 struct node{ ll w, len; int pos, dx; bool operator <(const node &x)const{
return x.w < w; } }point; priority_queue<node> q;//堆優化 inline void dijkstra(){ for(ri i = 1; i <= n; ++i) dis[i][0] = dis[i][1] = 1e18; dis[1][0] = dis[1][1] = 0; point.w = 0; point.pos = 1; point.len = 0; point.dx = 0; q.push(point); while(!q.empty()){ node tmp = q.top(); q.pop(); int x = tmp.pos, dx = tmp.dx; ll l = tmp.w, len = tmp.len; if(vis[x][dx]) continue; vis[x][dx] = 1; for(ri i = head[x]; i; i = E[i].nxt){ int y = E[i].v, type = E[i].type; ll w = E[i].w; if(type){ ll c = len + w; ll now = l - len * len + c * c;//這條小路對疲勞值的貢獻 if(now < dis[y][1]){ dis[y][1] = now; if(!vis[y][1]){ point.len = c; point.w = dis[y][1]; point.pos = y; point.dx = 1; q.push(point); } } } else{ if(l + w <= dis[y][0]){ dis[y][0] = l + w; if(!vis[y][0]){ point.w = dis[y][0]; point.pos = y; point.len = 0; point.dx = 0; q.push(point); } } } } } } int main(){ freopen("in.in", "r", stdin); freopen("out.out", "w", stdout); fast; cin >> n >> m; for(ri i = 1; i <= m; ++i){ int t, a, b; ll c; cin >> t >> a >> b >> c; add(a, b, c, t); add(b, a, c, t); } dijkstra(); cout << min(dis[n][0], dis[n][1]) << "\n"; return 0; }

這道題n比較小,可以直接用二維矩陣存路徑,記得要開long long