版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/88861429
title
随着新版百度空间的下线,Blog宠物绿豆蛙完成了它的使命,去寻找它新的归宿。
描述
给出一个有向无环的连通图,起点为1终点为N,每条边都有一个长度。绿豆蛙从起点出发,走向终点。
到达每一个顶点时,如果有K条离开该点的道路,绿豆蛙可以选择任意一条道路离开该点,并且走向每条路的概率为 1/K 。
现在绿豆蛙想知道,从起点走到终点的所经过的路径总长度期望是多少?
输入格式
第一行: 两个整数 N M,代表图中有N个点、M条边
第二行到第 1+M 行: 每行3个整数 a b c,代表从a到b有一条长度为c的有向边
输出格式
从起点到终点路径总长度的期望值,四舍五入保留两位小数。
样例输入
4 4
1 2 1
1 3 2
2 3 3
3 4 4
样例输出
7.00
数据范围与约定
对于20%的数据 N<=100
对于40%的数据 N<=1000
对于60%的数据 N<=10000
对于100%的数据 N<=100000,M<=2*N
analysis
设
表示从节点
走到终点所经过的路径的期望长度。若从
出发到有
条边,分别到达
,边长分别为
,则根据数学期望的定义和性质,有:
所以
,我们的目标是求出
。所以我们从终点出发,在反图上进行
,在拓扑排序的过程中顺便计算
即可。这个算法的时间复杂度是
。
code
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
int ver[maxn<<1],edge[maxn<<1],Next[maxn<<1],head[maxn],len;
inline void add(int x,int y,int z)
{
ver[++len]=y,edge[len]=z,Next[len]=head[x],head[x]=len;
}
int deg[maxn],out[maxn];
double dist[maxn];
queue<int>q;
int main()
{
int n,m;
read(n);read(m);
for (int i=1; i<=m; ++i)
{
int x,y,z;
read(x);read(y);read(z);
add(y,x,z);
++deg[x],++out[x];
}
q.push(n);
while (!q.empty())
{
int x=q.front();
q.pop();
for (int i=head[x]; i; i=Next[i])
{
int y=ver[i];
dist[y]+=(dist[x]+edge[i])/deg[y];
if (!--out[y]) q.push(y);
}
}
printf("%.2f\n",dist[1]);
return 0;
}