3036: 绿豆蛙的归宿
Time Limit: 2 Sec Memory Limit: 128 MBSubmit: 319 Solved: 224
[ Submit][ Status][ Discuss]
Description
随着新版百度空间的下线,Blog宠物绿豆蛙完成了它的使命,去寻找它新的归宿。
给出一个有向无环的连通图,起点为1终点为N,每条边都有一个长度。绿豆蛙从起点出发,走向终点。
到达每一个顶点时,如果有K条离开该点的道路,绿豆蛙可以选择任意一条道路离开该点,并且走向每条路的概率为 1/K 。
现在绿豆蛙想知道,从起点走到终点的所经过的路径总长度期望是多少?
Input
第一行: 两个整数 N M,代表图中有N个点、M条边
第二行到第 1+M 行: 每行3个整数 a b c,代表从a到b有一条长度为c的有向边
Output
从起点到终点路径总长度的期望值,四舍五入保留两位小数。
Sample Input
4 4
1 2 1
1 3 2
2 3 3
3 4 4
1 2 1
1 3 2
2 3 3
3 4 4
Sample Output
7.00
HINT
对于100%的数据 N<=100000,M<=2*N
Source
概率期望DP
f[i]表示从i到n的期望长度,则状态转移方程为:
f[i]=∑(f[e[i].to]+e[i].v)/outd[i]
其中outd[i]表示i点的出度,e[i].to是与i相连的点。
一个小的总结:如果一个点的每条出边概率相同,则逆向DP更加容易求解
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 100005
using namespace std;
int n,m,cnt,head[maxn];
double f[maxn];
bool vst[maxn];
struct edge_type{int next,to,v;}e[maxn*2];
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void add_edge(int x,int y,int v)
{
e[++cnt]=(edge_type){head[x],y,v};
head[x]=cnt;
}
inline void dfs(int x)
{
if (vst[x]) return;
vst[x]=true;
int outd=0;
for(int i=head[x];i;i=e[i].next)
{
dfs(e[i].to);
f[x]+=f[e[i].to]+e[i].v;
outd++;
}
if (!outd) return;
f[x]/=outd;
}
int main()
{
n=read();m=read();
F(i,1,m)
{
int x=read(),y=read(),z=read();
add_edge(x,y,z);
}
dfs(1);
printf("%.2lf\n",f[1]);
return 0;
}