分析
首先可以贪心得到,我们肯定优先走向期望天数小的节点。如果那个边未出现,才走其他的边。
同时,可以用像 Prim 的方法进行维护,每一次选出未用来更新的最小点,然后标记并更新其他未标记点。
同时,我们有:
[f_x=1+f_1p_{x,a_1}+f_2p_{x,a_2}(1-p_{x,a_1})+...+f_xp_{x,x}prod(1-p_{x,a_i})
]
然后还要考虑留在原地:
[f_x=frac{1+sumlimits_{i}f_{i}p_{x,i}prodlimits_{j=1}^{i-1}(1-p_{x,a_j})}{1-prodlimits_{i}(1-p_{x,a_i})}
]
然后可以发现直接维护 f 的值不方便,那么我们可以维护分子分母上的和式和积式。
code:
#include<bits/stdc++.h>
#define mp make_pair
using namespace std;
const int N=1e3+7;
int n;
double p[N][N];
double a[N],b[N];
bool vis[N];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
a[i]=b[i]=1;
for(int j=1;j<=n;j++){
scanf("%lf",&p[i][j]);
p[i][j]*=0.01;
}
}
a[n]=b[n]=0;
for(int i=1;i<=n;i++){
double res=1e20;
int o=0;
for(int j=1;j<=n;j++)
if(!vis[j]){
double f=a[j]/(1-b[j]);
if(res>f) res=f,o=j;
}
if(o==1){
printf("%.10lf
",res);
return 0;
}
vis[o]=1;
for(int j=1;j<=n;j++)
if(!vis[j]){
a[j]+=b[j]*p[j][o]*res;
b[j]*=1-p[j][o];
}
}
return 0;
}