【BZOJ3036】绿豆蛙的归宿 拓补排序+概率
【BZOJ3036】绿豆蛙的归宿
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
题解:反向建边,拓补排序的时候顺便推一下就ok了。
#include <cstdio> #include <cstring> #include <iostream> #include <queue> using namespace std; const int maxn=100010; int n,m,cnt; int to[maxn<<1],next[maxn<<1],head[maxn],d[maxn]; double f[maxn],val[maxn<<1],k[maxn]; queue <int> q; void add(int a,int b,int c) { to[cnt]=b; val[cnt]=c; next[cnt]=head[a]; head[a]=cnt++; } int main() { scanf("%d%d",&n,&m); memset(head,-1,sizeof(head)); int i,a,b,c,u; for(i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); add(b,a,c); k[a]++,d[a]++; } q.push(n); while(!q.empty()) { u=q.front(); q.pop(); for(i=head[u];i!=-1;i=next[i]) { d[to[i]]--; f[to[i]]+=(f[u]+val[i])/(1.0*k[to[i]]); if(!d[to[i]]) q.push(to[i]); } } printf("%.2f",f[1]); return 0; }
| 欢迎来原网站坐坐! >原文链接<