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
Never say never.


浙公网安备 33010602011771号