校内模拟赛 虫洞(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=,f=;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
for(;isdigit(ch);ch=getchar())x=x*+ch-'';return x*f;
} const int N = ;
struct Edge { int to, nxt; double w; } e[N << ];
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 = ; i <= n; ++i) dp[i] = 1e18, tp[i] = 1.0;
q.push(pa(, n)); dp[n] = ;
while (!q.empty()) {
int u = q.top().second; q.pop();
if (vis[u]) continue; vis[u] = ;
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] *= ( - e[i].w);
q.push(pa(dp[v], v));
}
}
}
printf("%.3lf\n", dp[]);
}
int main() {
n = read(), m = read();
for (int u, v, w, i = ; i <= m; ++i)
u = read(), v = read(), w = read(), add_edge(v, u, w);
Dijkstra();
return ;
}
上一篇:产品设计中先熟练使用铅笔 不要依赖Axure


下一篇:【转载】 Searching过程粗略梳理