luogu P4316 绿豆蛙的归宿|数论|数学期望|图论|拓扑排序
luogu P4316 绿豆蛙的归宿|数论|数学期望|图论|拓扑排序
Problem
分析
数论部分
数学期望:
F[x]表示从节点x走到终点所经过的路径的期望长度。
若从x出发有k条边,分别到达y1,y2,y3,...,yk,边长分别为z1,z2,...,zk
则根据数学期望的定义:
\[E\left ( X \right )= \sum P_i X_i,其中P_i表示发生该离散型随机事件概率,X_i表示随机变量取值
\]
以及数学期望的线性性质:
\[E\left ( X+Y \right )=E\left ( X \right )+E\left ( Y \right )
\]
得到:
\[F\left [ X \right ]=\frac{1}{k}\sum \begin{matrix}
k\\
i=1
\end{matrix}
\left ( F\left [ y_i \right ]+z_i \right)
\]
Code
F[v]+=(F[u]+w)/k[v];
图论部分:
拓扑排序:
显然,F[n]=0,求F[1]。
所以对反向图进行拓扑排序。
拓扑排序步骤:
先统计所有节点的入度
对于入度为0的节点就分离出来
把这个节点指向的节点入度-1
一直做修改,直到所有的节点都被分离出来
判断无解:
最后不存在入度为0的节点。
Code
void toposort(){
queue<int> q;q.push(n);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<g[u].size();i++){
int v=g[u][i].v,w=g[u][i].w;
F[v]+=(F[u]+w)/k[v];
if(rd[v]) rd[v]--;
if(rd[v]==0) q.push(v);
}
}
}
Code
#include <cstdio>
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
void read(int &n){
int num=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-') w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
num=num*10+ch-'0';
ch=getchar();
}
n=num*w;
}
const int maxn=100005;
struct node{int v,w;};
vector<node> g[maxn];
int n,m,rd[maxn],k[maxn];double F[maxn];
void toposort(){
queue<int> q;q.push(n);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<g[u].size();i++){
int v=g[u][i].v,w=g[u][i].w;
F[v]+=(F[u]+w)/k[v];
if(rd[v]) rd[v]--;
if(rd[v]==0) q.push(v);
}
}
}
int main(){
read(n);read(m);
for(int i=1;i<=m;i++){
int a,b,c;read(a);read(b);read(c);
g[b].push_back((node){a,c});//建反图
rd[a]++;k[a]++;
}
toposort();
printf("%.2lf",F[1]);
return 0;
}