逆向:
设E(i) 表示到i点到n点还需要的期望步数
仅考虑 x -> y这一条边,边权为w。
设 y 点所连的各个点的边权为
l
1
,
l
2
,
.
.
.
,
l
n
l_1,l_2,... ,l_n
l1,l2,...,ln,概率为
p
1
,
p
2
,
.
.
.
,
p
n
p_1,p_2,...,p_n
p1,p2,...,pn
那么 E(y) =
p
1
l
1
+
p
2
l
2
+
.
.
.
+
p
n
l
n
p_1l_1 + p_2l_2 + ... + p_nl_n
p1l1+p2l2+...+pnln
E(x) =
p
1
(
l
1
+
w
)
+
p
2
(
l
2
+
w
)
+
.
.
.
+
p
n
(
l
n
+
w
)
p_1(l_1+w) + p_2(l_2+w) + ... + p_n(l_n+w)
p1(l1+w)+p2(l2+w)+...+pn(ln+w)
即等于 E(y) +
w
∗
∑
i
=
1
n
p
i
w*\sum_{i=1}^{n}p_i
w∗∑i=1npi
注意理解
p
i
p_i
pi的含义,表示为y点到它后面连接点的概率。
那
∑
i
=
1
n
p
i
=
1
\sum_{i=1}^{n}p_i = 1
∑i=1npi=1
即 E(x) = E(y) + w
注意是当仅考虑 x -> y一条边时,那么考虑多边。
E(x) = (E(y) + w) *
p
i
p_i
pi,此时的概率就为x的出度的数量。
正向:
设E(i) 表示到1~i点需要的期望步数
仅考虑 x -> y这一条边,边权为w。
设 x 点所连的各个点的边权为
l
1
,
l
2
,
.
.
.
,
l
n
l_1,l_2,... ,l_n
l1,l2,...,ln,概率为
p
1
,
p
2
,
.
.
.
,
p
n
p_1,p_2,...,p_n
p1,p2,...,pn
那么 E(x) =
p
1
l
1
+
p
2
l
2
+
.
.
.
+
p
n
l
n
p_1l_1 + p_2l_2 + ... + p_nl_n
p1l1+p2l2+...+pnln
E(y) =
p
1
(
l
1
+
w
)
+
p
2
(
l
2
+
w
)
+
.
.
.
+
p
n
(
l
n
+
w
)
p_1(l_1+w) + p_2(l_2+w) + ... + p_n(l_n+w)
p1(l1+w)+p2(l2+w)+...+pn(ln+w)
即等于 E(x) +
w
∗
∑
i
=
1
n
p
i
w*\sum_{i=1}^{n}p_i
w∗∑i=1npi
注意理解
p
i
p_i
pi的含义,表示为i点到它后面的x点的概率。
那
∑
i
=
1
n
p
i
≠
1
\sum_{i=1}^{n}p_i \neq 1
∑i=1npi=1
举个例子: a -> x ,a -> b 那么a到x的概率为
1
2
\frac{1}{2}
21
所以上述维护上述两个变量E和p就行。
逆向代码:
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int e[N],ne[N],h[N],w[N],idx=1;
int si[N],n,m,d[N];
double dp[N];
void add(int a,int b,int c){
w[idx]=c,e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void top_sort(){
queue<int> qe;
qe.push(n);
while(!qe.empty()){
int t = qe.front();qe.pop();
for(int i=h[t];i;i=ne[i]){
int j = e[i];
dp[j] += (w[i] + 1.0 * dp[t]) / si[j];
if(--d[j] == 0) qe.push(j);
}
}
cout<<fixed<<setprecision(2)<<dp[1]<<endl;
}
signed main(){
IOS
cin>>n>>m;
for(int i=1;i<=m;i++){
int a,b,c; cin>>a>>b>>c;
add(b,a,c);
d[a] ++;
si[a] ++;
}
top_sort();
return 0;
}