校内模拟赛 虫洞(by NiroBC)
题意:
n个点m条边的有向图,每一天每条边存在的概率都是p,在最优策略下,询问从1到n的期望天数。
分析:
dijkstra。
每次一定会优先选dp最小的后继走,如果这条边不存在,选次小的,以此类推。
dp[i]表示从i开始到n的期望天数,从后往前推,每次取出dp最小的,更新其他点。
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cctype> #include<cmath> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #define pa pair<double,int> #define fore(i, u, v) for (int i = head[u], v = e[i].to; i; i = e[i].nxt, v = e[i].to) using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 200005; struct Edge { int to, nxt; double w; } e[N << 1]; int head[N], En, n, m; double P[N], dp[N], sp[N], s[N], tp[N]; bool vis[N]; inline void add_edge(int u,int v,int w) { ++En; e[En].to = v, e[En].w = 1.0 * w / 100.0, e[En].nxt = head[u]; head[u] = En; } void Dijkstra() { priority_queue< pa, vector< pa >, greater< pa > > q; for (int i = 1; i <= n; ++i) dp[i] = 1e18, tp[i] = 1.0; q.push(pa(0, n)); dp[n] = 0; while (!q.empty()) { int u = q.top().second; q.pop(); if (vis[u]) continue; vis[u] = 1; fore(i, u, v) { double sum = s[v] + dp[u] * e[i].w * tp[v]; double sump = sp[v] + e[i].w * tp[v]; if (dp[v] > (sum + 1.0) / sump) { dp[v] = (sum + 1.0) / sump; s[v] += dp[u] * e[i].w * tp[v]; sp[v] += e[i].w * tp[v]; tp[v] *= (1 - e[i].w); q.push(pa(dp[v], v)); } } } printf("%.3lf\n", dp[1]); } int main() { n = read(), m = read(); for (int u, v, w, i = 1; i <= m; ++i) u = read(), v = read(), w = read(), add_edge(v, u, w); Dijkstra(); return 0; }