解法
(好像在哪里见过几乎一样的问题?)
考虑这种图上的期望一般倒着算,所以可以从终点反推回起点。
然后考虑我们更新点到终点的距离的过程,我们每次选出一个目前到终点距离最近的点,用它去更新和它相邻的点的距离,这个是也是最短路的思想。由于没有负权边,所以考虑用迪杰斯特拉
转移方程
d
[
u
]
=
∑
v
d
[
v
]
∗
p
[
u
]
[
v
]
∗
(
1
−
p
r
[
u
]
)
,
更
新
的
时
候
按
d
从
小
到
大
的
顺
序
d[u]=\sum_v d[v]*p[u][v]*(1-pr[u]),更新的时候按d从小到大的顺序
d[u]=∑vd[v]∗p[u][v]∗(1−pr[u]),更新的时候按d从小到大的顺序
d
[
i
]
:
i
到
n
的
最
小
期
望
d[i]:i到n的最小期望
d[i]:i到n的最小期望
p
r
[
i
]
:
i
已
经
转
移
走
的
概
率
(
d
j
更
新
的
时
候
需
要
)
pr[i]:i已经转移走的概率(dj更新的时候需要)
pr[i]:i已经转移走的概率(dj更新的时候需要)
s
u
m
[
i
]
:
已
经
计
算
过
的
到
i
的
期
望
sum[i]:已经计算过的到i的期望
sum[i]:已经计算过的到i的期望
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char c=getchar();int t=0,f=1;
while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
while((isdigit(c))&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
return t*f;
}
int n,vis[1005],a[1005];
double p[1005][1005],d[1005],pr[1005],sum[1005];
signed main(){
n=read();
for(int i=1;i<=n;i++){
int x=0;
sum[i]=pr[i]=1.0;
for(int j=1;j<=n;j++){
x=read();
p[i][j]=x*0.01;
}
}
vis[n]=1;
a[1]=n;d[0]=1e18;
for(int i=2;i<=n;i++){
for(int j=1;j<=n;j++){
if(vis[j])continue;
sum[j]+=d[a[i-1]]*p[j][a[i-1]]*pr[j];
pr[j]*=(1-p[j][a[i-1]]),d[j]=sum[j]/(1-pr[j]);
}
int pos=0;
for(int j=1;j<=n;j++){
if((!vis[j])&&(d[j]<d[pos]))pos=j;
}
vis[pos]=1;a[i]=pos;
}
printf("%.10lf\n",d[1]);
return 0;
}