有一个 (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];
}
}
}