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

posted @ 2020-08-16 15:20  kojoker  阅读(212)  评论(1)    收藏  举报