题意:
给定一个环上的四个点1,2,3,4,距离分别为d12,d23,d34,d41,要求从2号点出发,最后回到2号点,要求经过的距离为大于等于 K 的最小值,求该最小值。
参考:
1. http://blog.csdn.net/blessLZH0108/article/details/76690027?locationNum=6&fps=1 ——Alzh
2. https://post.icpc-camp.org/d/674-poi-x-sums/6 POI X Sums
思路:
详细分析参见链接 2
考虑 dist[i][r] 为走到 i 号点的路径中 % mod = r 的最小值,则 dist[i][r] + mod, dist[i][r] + 2 * mod, ..., dist[i][r] + t * mod 均可以取到,而 dist[i][r] 为 % mod = r 的剩余类中的最小值。这里的 mod 值为 d12 与 d13 中的任一个值的两倍,对上述 均可以取到 的理解即为在距离不够时可以通过来回走这一段来补充距离。
个人觉得 d12 和 d13 随便取哪个都无所谓,之所以取小的不是因为正确性,而是因为空间与时间的考虑(如果说的不对还请麻烦告诉我Orz)
所以我们只需要用最短路处理出所有的 dist[i][j] (1 <= i <= 4, 0 <= j < mod) 的最小值即可。
具体操作时,dist[e.from][dist % mod] + e.dist < dist[e.to][(dist + e.dist) % mod] 时进行松弛。
处理出 dist 数组之后,只需要看 dist[2] 这一维。
如果 dist[2][i] <= k, 说明 dist[2][i] 可以通过加上若干个 mod 去得到大于等于 k 的最小值,反过来也就是 k 通过减去若干个 mod 可以得到 0 ~ mod - 1 范围内的一个值,不妨记为 kmod = k % mod, 那么 i >= kmod 时,i - kmod 即为超出的部分;否则 mod - (kmod - i) 即为超出的部分(想想也很直观);
如果 dist[2][i] > k, 那么超出的部分即为 dist[2][i] - k,
最后所有超出的部分取个最小值即为答案。
Code:
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f3f3f3f3f
typedef long long LL;
using namespace std;
struct qnode {
LL src, r;
LL dist;
qnode(LL _src = 0, LL _r = 0, LL _d = 0) : src(_src), r(_r), dist(_d) {}
bool operator < (const qnode& q) const { return dist > q.dist; }
};
struct Edge {
LL to, ne; LL dist;
Edge(LL v = 0, LL d = 0, LL next = 0) : to(v), dist(d), ne(next) {}
}edge[10];
LL tot, ne[10], d[10];
void add(LL u, LL v, LL d) {
edge[tot] = Edge(v, d, ne[u]);
ne[u] = tot++;
}
priority_queue<qnode> q;
LL dist[5][60010], k;
inline LL min(LL a, LL b) { return a < b ? a : b; }
void bfs(LL src) {
LL mod = 2LL * min(d[1], d[2]);
for (LL i = 1; i <= 4; ++i) {
for (LL j = 0; j < mod; ++j) dist[i][j] = inf;
}
q.push(qnode(src, 0, 0)); dist[2][0] = 0;
while (!q.empty()) {
// printf("%d\n", q.size());
qnode nowf = q.top(); q.pop();
LL u = nowf.src, x = nowf.r;
if (nowf.dist > dist[u][x] || nowf.dist >= k + mod) continue;
for (LL i = ne[u]; i != -1; i = edge[i].ne) {
Edge e = edge[i]; LL v = e.to, nx = (x + e.dist) % mod;
if (dist[u][x] + e.dist < dist[v][nx]) {
dist[v][nx] = dist[u][x] + e.dist;
q.push(qnode(v, nx, dist[v][nx]));
}
}
}
LL kmod = k % mod;
LL diff = mod;
for (LL i = 0; i < mod; ++i) {
if (dist[2][i] <= k) {
if (i >= kmod) diff = min(diff, (LL)i - kmod);
else diff = min(diff, (LL)mod - (kmod - i));
}
else diff = min(diff, dist[2][i] - k);
}
printf("%lld\n", k + diff);
}
void work() {
memset(ne, -1, sizeof(ne)); tot = 0;
scanf("%lld%lld%lld%lld%lld", &k, &d[1], &d[2], &d[3], &d[4]);
for (LL i = 1; i <= 4; ++i) {
LL from = i, to = i % 4 + 1;
add(from, to, d[i]); add(to, from, d[i]);
}
bfs(2);
}
int main() {
LL T;
scanf("%lld", &T);
while (T--) work();
return 0;
}