luogu P4316 绿豆蛙的归宿|数论|数学期望|图论|拓扑排序

luogu P4316 绿豆蛙的归宿|数论|数学期望|图论|拓扑排序

Problem

Problem


分析

数论部分

数学期望:

F[x]表示从节点x走到终点所经过的路径的期望长度。
若从x出发有k条边,分别到达y1,y2,y3,...,yk,边长分别为z1,z2,...,zk

则根据数学期望的定义

[Eleft ( X ight )= sum P_i X_i,其中P_i表示发生该离散型随机事件概率,X_i表示随机变量取值 ]

以及数学期望的线性性质:

[Eleft ( X+Y ight )=Eleft ( X ight )+Eleft ( Y ight ) ]

得到:

[Fleft [ X ight ]=frac{1}{k}sum egin{matrix} k\ i=1 end{matrix} left ( Fleft [ y_i ight ]+z_i ight) ]

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;
}
原文地址:https://www.cnblogs.com/saitoasuka/p/10337553.html