绿豆蛙的归宿

绿豆蛙的归宿

题目描述

给出张 n 个点 m 条边的有向无环图,起点为 1,终点为 n,每条边都有一个长度,并且从起点出发能够到达所有的点,所有的点也都能够到达终点。

绿豆蛙从起点出发,走向终点。 到达每一个顶点时,如果该节点有 k 条出边,绿豆蛙可以选择任意一条边离开该点,并且走向每条边的概率为 \(\frac{1}{k}\) 。现在绿豆蛙想知道,从起点走到终点的所经过的路径总长度期望是多少?

输入格式

输入的第一行是两个整数,分别代表图的点数 n 和边数 m

第 2 到第(m+1) 行,每行有三个整数 u, v, w,代表存在一条从u 指向v 长度为w 的有向边。

输出格式

输出一行一个实数代表答案,四舍五入保留两位小数。

输入输出样例

输入 #1

1
2
3
4
5
4 4 
1 2 1
1 3 2
2 3 3
3 4 4

输出 #1

1
7.00

说明/提示

数据规模与约定

  • 对于100% 的数据,保证 1≤n≤105,1≤m≤2×n,1≤u,vn,1≤w≤109,给出的图无重边和自环。

思路

一般的期望dp都可以考虑正推或逆推,更关键的是要得出递推公式

初状态已知就正推,末状态已知就正推

考虑到此题的图的结构我们使用拓扑序加bfs来保证dp更新的顺序正确

正推

设dp[i]表示从1到i的期望路径长度

g[i]表示从1到i的概率

从i出发,有k条路径,分别到达j1,j2,...,jn,路程为w1,w2,...,wn

则可得\(dp[j]=(dp[i]+w_i\times g[i]/k)\) , \(g[j]=g[i]/k\)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N=1e5+10;
struct node{
int v,w;
};
double dp[N],g[N];
int in[N],out[N];
vector<node>t[N];
void bfs(int u){
g[1]=1;
queue<int>q;
q.push(1);
while(!q.empty()){
u=q.front();
q.pop();
for(auto v:t[u]){
dp[v.v]+=1.0*(dp[u]+g[u]*v.w)/t[u].size();
g[v.v]+=1.0*g[u]/t[u].size();
in[v.v]--;
if(in[v.v]==0)q.push(v.v);
}
}
}
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v,c;
cin>>u>>v>>c;
t[u].push_back({v,c});
in[v]++;
out[u]++;
}

bfs(1);
printf("%.2f",dp[n]);
return 0;
}

逆推

dp[i]表示i到终点经过的路径的期望长度

从i出发,有k条路径,分别到达j1,j2,...,jn,路程为w1,w2,...,wn

\(dp[i]=\frac{1}{k}\times(dp[j_1]+w_1)+\frac{1}{k}\times(dp[j_2]+w_2)+...+\frac{1}{k}\times(dp[j_k]+w_k)=\sum_{i=1}^kdp[j_i]+w_i\)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N=1e5+10;
struct node{
int v,w;
};
double dp[N],g[N];
int in[N],siz[N];
vector<node>t[N];
void bfs(int u){
queue<int>q;
q.push(u);
while(!q.empty()){
u=q.front();
q.pop();
for(auto v:t[u]){
dp[v.v]+=1.0*(dp[u]+v.w)/siz[v.v];
in[v.v]--;
if(in[v.v]==0)q.push(v.v);
}
}
}
int main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++){
int u,v,c;
cin>>u>>v>>c;
t[v].push_back({u,c});
in[u]++;
siz[u]++;
}

bfs(n);
printf("%.2f",dp[1]);
return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!