#include "cyberland.h"
#include <vector>
#include <queue>
#include <functional>
#include <cmath>
using namespace std;
typedef long double ld;
const ld INF = 1e18;
double solve(int N, int M, int K, int H,
std::vector<int> x, std::vector<int> y,
std::vector<int> c, std::vector<int> arr) {
// Build the undirected graph.
vector<vector<pair<int,int>>> adj(N);
for (int i = 0; i < M; i++) {
int u = x[i], v = y[i], w = c[i];
adj[u].push_back({v, w});
adj[v].push_back({u, w});
}
// DFS from node 0 (source) but stop if H is reached.
// Only nodes visited here are considered "reachable" (by 0 without passing through H).
vector<bool> reachable(N, false);
function<void(int)> dfs = [&](int u) {
reachable[u] = true;
for (auto &edge : adj[u]) {
int v = edge.first;
if (v == H) continue; // do not traverse beyond H
if (!reachable[v]) dfs(v);
}
};
dfs(0);
// Reverse Dijkstra: We start at H and only relax edges to nodes that were marked reachable.
// Here the state is (node, used) where used is the number of divide-by-2 abilities already used.
// When moving from a state (u, used) to neighbor v along an edge of weight w,
// we add an extra cost of w / (2^(used)).
// Additionally, if u has the divide-by-2 ability (arr[u]==2) and used < K,
// we may “activate” it: in the reverse search this means the total cost becomes d/2,
// and future edges will be divided by a larger power of 2.
int K_lim = K; // we use K as given (if needed, one could cap it at 100 as per the outline)
vector<vector<ld>> dist(N, vector<ld>(K_lim+1, INF));
struct State {
ld cost;
int node, used;
};
auto cmp = [&](const State &a, const State &b) { return a.cost > b.cost; };
priority_queue<State, vector<State>, decltype(cmp)> pq(cmp);
// Start from Cyberland (node H) with cost 0 and no divide ability used.
dist[H][0] = 0;
pq.push({0, H, 0});
while (!pq.empty()) {
State cur = pq.top();
pq.pop();
ld d = cur.cost;
int u = cur.node, used = cur.used;
if (d != dist[u][used]) continue;
// If we have reached node 0 or a node whose ability clears (arr[u]==0),
// then this state gives the minimum possible total cost.
if (u == 0 || arr[u] == 0)
return (double)d;
// Option 1: Use divide-by-2 ability at node u if available.
// (This “activates” the ability in reverse, which halves the current cost.)
if (arr[u] == 2 && used < K_lim) {
ld nd = d / 2.0;
if (nd < dist[u][used+1]) {
dist[u][used+1] = nd;
pq.push({nd, u, used+1});
}
}
// Option 2: Relax all edges from node u.
// The cost to go from u to a neighbor v is increased by (edge weight) / (2^(used)).
// We use powl to compute 2^(used) in long double.
ld discount = powl(2.0L, used);
for (auto &edge : adj[u]) {
int v = edge.first;
int w = edge.second;
if (!reachable[v]) continue; // only consider nodes reachable from 0.
ld nd = d + ((ld)w) / discount;
if (nd < dist[v][used]) {
dist[v][used] = nd;
pq.push({nd, v, used});
}
}
}
return -1;
}
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |