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;
}
posted @ 2026-09-20 16:22  wmq2012  阅读(13)  评论(0)    收藏  举报