【Codeforces 605E】Intergalaxy Trips

期望dp,贪心。

题目大意:

给定一张有向图,每天每条边都有一定概率出现。

从 $1$ 出发要走到 $n$,每天可以走一条出现的边或者原地不动。

求最优策略下走到 $n$ 的期望天数。

题解:

类似 Dijkstra 最短路算法的贪心思路。

令 $f_i$ 表示从 $i$ 走到 $n$ 的期望天数。

假设我们当前已经确定期望的点的序列按期望从小到大排序后为 $a_1,a_2,\ldots,a_k$,那么我们每次只从 $a$ 中的点转移。

从这些集合进行转移得到的其他点的期望步数中,我们取期望最小的那个插入 $a$ 的最后面。

期望小的点显然不会从其他期望大的点转移过来,而期望大的点可能从期望小的点转移过来。我们每次取的是当前集合转移到的期望最小的点,那么这个点的最小期望就是计算出来的值。

考虑如何计算这个期望。

我们显然直接走到期望尽可能小的点,因此:

这些信息每次从上一轮计算的结果继承下来继续计算即可。

时间复杂度 $O(n^2)$。

Code:

#include<cstdio>
const int N=1e3+6;
double P[N][N],f[N],E[N],p[N];
bool vis[N];
int n;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    for(int j=1,k;j<=n;++j)scanf("%d",&k),P[i][j]=k/100.;
    f[n]=0;
    vis[n]=1;
    for(int i=1;i<n;++i)p[i]=1-P[i][n],E[i]=1;
    for(int T=1;T<n;++T){
        int u=0;double ff=1e18;
        for(int i=1;i<n;++i)if(!vis[i]){
            double g=E[i]/(1-p[i]);
            if(g<ff)u=i,ff=g;
        }
        f[u]=ff,vis[u]=1;
        for(int i=1;i<n;++i)if(!vis[i])
        E[i]=E[i]+p[i]*P[i][u]*ff,p[i]*=1-P[i][u];
    }
    printf("%.100f\n",f[1]);
    return 0;
}