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);
}