CF605E Intergalaxy Trips 题解
笔记列表
高级题目好高级好高级搞机好搞机好
依旧是期望考虑倒退
设 \(f_i\) 表示 \(i\) 到 \(n\) 的期望天数
那么你对 \(f_i\) 转移的时候肯定会去找它能走到的期望天数最小的点 \(j\) 转移
并且这个 \(f_j < f_i\) 因为如果现在走到了一个更劣质的点。
那我还不如在这里原地等一天,所以走期望天数大于当前点的点一定是不优的
所以现在分为两种情况
1
- 现在存在能到达的 \(f_j < f_i\) 的 \(j\),那么就会走最小的 \(f_j\),那么这说明比 \(f_j\) 更小的 \(f_k\) 是无法到达的,否则就会走 \(k\)
- 这一部分的期望和
\[\sum_{j}^{f_j < f_i} p_{i,j}\times\prod_{k}^{f_k<f_j}(1-p_{i,k}) \times f_j
\]
- 乘以 \(p_{i,j}\) 需要满足 \(i\) 能到达 \(j\)
- 后面的累乘需要满足 比 \(j\) 更优秀 \(k\) 无法到达
- 这些值我们走 \(j\) 的概率, 在乘以 \(f_j\) 得到期望天数
2
- 现在所有 \(f_j < f_i\) 的 \(j\) 都无法到达,所以会选择在原地休息一天
- 这一部分的期望和
\[\prod_{j}^{f_j < f_i} (1-p_{i,j}) \times f_i
\]
- 前面乘上更有的点都无法到达的概率,然后乘以 \(f_i\) 变成天数期望
然后就得到了转移公式
\[f_i = 1 + \sum_{j}^{f_j < f_i} p_{i,j}\times\prod_{k}^{f_k<f_j}(1-p_{i,k}) \times f_j + \prod_{j}^{f_j < f_i} (1-p_{i,j}) \times f_i
\]
- 为什么两种情况可以直接加起来
- 因为两种情况会发生其中一件且只会发生其中一件,没有别的选择
- 为什么最前面要\(+1\)
- 因为两种选择不管发生了哪一个,都过去了一天
- 为什么不是两种情况各 \(+1\)
- 因为 \(+1\) 表示两种情况经过这一天的概率和为 \(1\)
把转移公式移项
\[f_i =\frac{\sum_j^{f_j<f_i}p_{i,j}f_j\prod_k^{f_k<f_j}(1-p_{i,k})+1}{1-\prod_{j}^{f_j<f_i}(1-p_{i,j})}
\]
那么接下来的实现步骤就类似于 \(Dijkstra\)
每一次去找最小的 \(f_i\) 取更新别人
初始从 \(f_n\) 开始走
答案是 \(f_1\)
然后为了方便转移
记 \(h_i = \prod_{j}^{f_j<f_i}(1-p_{i,j})\) 表示比\(i\) 优秀的点无法到达
记 \(g_i = \sum_j^{f_j<f_i}p_{i,j}f_j\prod_k^{f_k<f_j}(1-p_{i,k})+1\)
所以 \(f_i = \frac{g_i}{1-h_i}\)
然后你用 \(u\) 去更新 \(v\)
\[g_v\gets g_v+p_{v,u}\times f_u\times h_v
\]
\[h_v \gets h_v \times (1-p_{v,u})
\]
\[f_v = \frac{g_v}{1-h_v}
\]
注意读入 \(p_{u,v}\) 用整形读入在 \(/100\) 不然直接用浮点数读就超时了
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define fore(i,a,b) for( int i=(a); i<=(b); ++i)
#define repe(i,a,b) for( int i=(a); i>=(b); --i)
using namespace std;
const int N = 3010;
int n;
double p[N][N];
double f[N], g[N], h[N];
bool vis[N];
queue<int> q;
signed main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
cin >> n;
fore(i, 1, n) {
fore(j, 1, n) {
int in; cin >> in;
p[i][j] = in / 100.0;
}
h[i] = 1;
g[i] = 1;
}
q.push(n);
while(!q.empty()) {
int u = q.front();
q.pop();
if(vis[u]) continue;
vis[u] = 1;
int nxt = 0;
fore(v, 1, n) {
if(vis[v]) continue;
g[v] += f[u] * p[v][u] * h[v];
h[v] *= (1 - p[v][u]);
f[v] = g[v] / (1 - h[v]);
if(nxt == 0 || f[v] < f[nxt]) nxt = v;
}
q.push(nxt);
}
printf("%.9lf", f[1]);
return 0;
}
本文来自博客园,作者:wmq2012,转载请注明原文链接:https://www.cnblogs.com/wmq2012/p/23050047

浙公网安备 33010602011771号