CCF 201712-04 行车路线_Dijkstra变形

201712-04行车路线 传送门

这看似是一个很复杂的问题, 实际上, 额…

首先它有基础的最短路问题的影子,题目有20%的数据是没有小道的,可用Dijkstra算法直接求那么本着那更多的部分分的战略, 我们先写基础程序(先假设全部都是大道)

OK, 初稿裸的dijkstra是20分, 那么考试的时候这20分也比较稳了, 距离满分也只有80分罢了… 罢了… 罢了…

查看数据描述:

对于30%的评测用例,1 ≤ n ≤ 8,1 ≤ m ≤ 10 这句话告诉我们即使想不出正解, 正确的暴力也是可以得到30分的.

对于另外20%的评测用例,所有的小道不相交 小道不相交意味着什么?意味着我们不用考虑连续的小道,那么不用正解也是可以的到这40分的, 因为这样的话, 小道的权值就直接变成它长度的平方了.那么开始水第二版

OK, 第二版提交上去,得了60分了,并没有花多少功夫,也不难. 所以按照这种难度上300分还是挺有希望的

那么剩下的数据已经不算小了1 ≤ n ≤ 500,1 ≤ m ≤ 105,1 ≤ a, b ≤ n,t是0或1,c ≤ 105。,要拿满分必定是要正解的, 虽然这个数据来看可能并不需要优化.

剩下的问题就是,如何在最短路问题中,解决小道可能连起来的问题.乍一看很玄,没什么思路.

我想, 获取可以复杂化这个dis数组,改成结构体,存储距离的同时存储它的大小道性质以及小道长度. 这样的话,那么从一个结点到另一个结点,这个结点是小道还是大道会影响后面最短路的选择吗?

似乎是会的: 思考这样一种情况: 现在从A节点更新到B节点,A结点选的是小道,这种情况下A-B选大道更优,可是实际情况是,如果A结点选大道,A-B选小道可以获得更优的结果.那么得不出正确的解.

后面的最优解可能是从前面的次优解继承过来的. 但我们可以发现,能够利用的A结点信息最多只有两种,分别是大道和小道,那么我们是否可以同时对一个存储这两种路径的解呢? 应该是可行的.直觉告诉我,这就是正解了.

结果得了70, 这么复杂的程序, 到头来也不知道是我思路错了还是实现错了.

搜博客之后, 发现把int改成long long, 结果得了90分, 最后10分也不知道那里错了.

附90分代码.

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;

struct Node {
    long long to, val;
    bool isb;
    Node (long long t, long long v, long long i) : to(t), val(v), isb(i) {}
};

struct Dis {
    long long last, dis; // if !big (small), then how long before.
}; 

const long long maxn = 505, INF = 0x3f3f3f3f;
vector<Node> G[maxn];
long long n, m, vis[maxn] = {};
Dis dis[maxn][2];

void Dijkstra()
{
    dis[1][0].dis = dis[1][1].dis = 0;
    for (long long k = 0; k < n; ++k) {
        long long u = -1, _min = INF;
        for (long long i = 1; i <= n; ++i) {
            if (!vis[i] && (dis[i][0].dis < _min || dis[i][1].dis < _min)) {
                _min = min(dis[i][0].dis, dis[i][1].dis);
                u = i;
            }
        }
        vis[u] = true;
        for (long long i = 0, v, w; i < G[u].size(); ++i) {
            v = G[u][i].to, w = G[u][i].val;
            if (!G[u][i].isb) {
                if (w + dis[u][0].dis < dis[v][0].dis) dis[v][0].dis = w + dis[u][0].dis;
                if (w + dis[u][1].dis < dis[v][0].dis) dis[v][0].dis = w + dis[u][1].dis;
            } else {
                if (dis[u][0].dis + w * w < dis[v][1].dis) {
                    dis[v][1].dis = dis[u][0].dis + w * w;
                    dis[v][1].last = w;
                }
                if (dis[u][1].last != -1) {
                    long long d = dis[u][1].dis + (dis[u][1].last + w)*(dis[u][1].last + w) - dis[u][1].last*dis[u][1].last;
                    dis[v][1].dis = min(dis[v][1].dis, d);
                    dis[v][1].last = dis[u][1].last + w;
                }
            }
        }
    }
}

int main()
{
    for (long long i = 0; i < maxn; ++i) {
        dis[i][0].dis = dis[i][1].dis = INF;
        dis[i][0].last = dis[i][1].last = -1;
    }
    cin >> n >> m;
    for (long long i = 0, a, b, c, d; i < m; ++i) {
        cin >> a >> b >> c >> d;
        G[b].push_back(Node(c, d, a));
        G[c].push_back(Node(b, d, a));
    }
    Dijkstra();
    cout << min(dis[n][0].dis, dis[n][1].dis);
}
    原文作者:Dijkstra算法
    原文地址: https://blog.csdn.net/wjh2622075127/article/details/81435902
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞