CF605E Intergalaxy Trips 【贪心,动态规划,期望】

有一个 \(n\) 个点的有向完全图,每个时刻 \(i\)\(j\)\(p_{i,j}\) 的概率存在一条边。每个时刻可以走一条边或留在原地,求从 \(1\)\(n\) 的最优期望时间。

\(n\le 10^3\)


用类似 dijkstra 的方法,按期望时间从小到大更新别的点,\(E_x\) 表示从 \(x\) 走到 \(n\) 的最短期望时间。

\[E_x=\sum_iE_ip_{xi}\prod_j(1-p_{xj}) \]

(取当前出现的所有边中期望最小的那个走)

然而其实你是要去掉一条边都走不出去的概率的,也就是除以 \(1-\prod_i(1-p_{xi})\),其中 \(i\) 是目前能用于更新的边的另一个端点。

#include<bits/stdc++.h>
#define Rint register int
using namespace std;
template<typename T>
inline void read(T &x){
    int ch = getchar(); x = 0;
    for(;ch < '0' || ch > '9';ch = getchar());
    for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
}
template<typename T>
inline bool chmax(T &a, const T &b){if(a < b) return a = b, 1; return 0;}
template<typename T>
inline bool chmin(T &a, const T &b){if(a > b) return a = b, 1; return 0;}
const int N = 1003;
int n;
double p[N][N], prod[N], E[N];
bool vis[N];
int main(){
    read(n);
    for(Rint i = 1;i <= n;++ i)
        for(Rint j = 1;j <= n;++ j)
            read(p[i][j]), p[i][j] /= 100;
    if(n == 1) return puts("0"), 0;
    for(Rint i = 1;i <= n;++ i){
        E[i] = 1; prod[i] = 1 - p[i][n];
    }
    E[n] = 0; vis[n] = true;
    for(Rint i = 1;i <= n;++ i){
        int u = 0; double tmp = 1e18;
        for(Rint j = 1;j <= n;++ j)
            if(!vis[j] && chmin(tmp, E[j] / (1 - prod[j]))) u = j;
        vis[u] = true;
        if(u == 1) return printf("%.6lf\n", tmp), 0;
        for(Rint j = 1;j <= n;++ j){
            E[j] += tmp * p[j][u] * prod[j];
            prod[j] *= 1 - p[j][u];
        }
    }
}
posted @ 2020-05-03 21:49  mizu164  阅读(144)  评论(0编辑  收藏  举报