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

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

(nle 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
", tmp), 0;
        for(Rint j = 1;j <= n;++ j){
            E[j] += tmp * p[j][u] * prod[j];
            prod[j] *= 1 - p[j][u];
        }
    }
}
原文地址:https://www.cnblogs.com/AThousandMoons/p/12823728.html