题解:P14318 「ALFR Round 11」B 行走 (walk)
Wyh_dailyAC · · 题解
思路
本题不难,主要在代码。
由于走过一条边权值就变回
那么可以将附加权值看作削了一个人的最短路上的一条边。
一股脑加一条边上好,还是均摊着加好?显然是均摊着加好(读者自证)。
所以直接按此贪心策略作答即可。
Code
::::info[Code]
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
#define int long long
vector<int> E[N];
struct nd {
int u, s;
nd(long long _u = 0, long long _s = 0): u(_u), s(_s) {}
};
void solve() {
int n, m, k; cin >> n >> m >> k;
for (int i = 1, u, v; i <= m; ++i) {
cin >> u >> v;
E[u].emplace_back(v), E[v].emplace_back(u);
}
int x1, y1, x2, y2; cin >> x1 >> y1 >> x2 >> y2;
vector<int> vis(n + 5);
queue<nd> q;
q.emplace(x1, 0);
nd ans1 = {y1, -0x3f};
while (!q.empty()) {
auto [u, s] = q.front(); q.pop();
if (u == y1) {
ans1 = {u, s};
break;
}
if (vis[u]) continue;
vis[u] = 1;
for (auto v : E[u]) {
q.emplace(v, s + 1);
}
}
while (!q.empty()) q.pop();
fill(vis.begin(), vis.end(), 0);
q.emplace(x2, 0);
nd ans2 = {y2, -0x3f};
while (!q.empty()) {
auto [u, s] = q.front(); q.pop();
if (u == y2) {
ans2 = {u, s};
break;
}
if (vis[u]) continue;
vis[u] = 1;
for (auto v : E[u]) {
q.emplace(v, s + 1);
}
}
if (ans1.s == -0x3f || ans2.s == -0x3f) {
cout << "-1\n";
for (int i = 1; i <= n; ++i) E[i].clear();
return;
}
int ans = ans1.s + ans2.s;
if (k == 0 || ans == 0) {
cout << ans << "\n";
for (int i = 1; i <= n; ++i) E[i].clear();
return;
}
if (ans >= k) {
int tmp = ans - k;
long double fans = (long double) 1.0 * k / 2.0;
fans += (long double) 1.0 * tmp;
cout << fixed << setprecision(15) << fans << "\n";
} else {
int ttmp = k / ans;
int tmp = ans - k % ans;
long double fans = (long double) 1.0 * tmp / (1.0 + ttmp);
fans += (long double) 1.0 * (k % ans) / (2.0 + ttmp);
cout << fixed << setprecision(15) << fans << "\n";
}
for (int i = 1; i <= n; ++i) E[i].clear();
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T; cin >> T;
while (T--) solve();
}
::::