题干:
随着新版百度空间的下线,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
Sample Output
7.00
Hint
对于100%的数据 N<=100000,M<=2*N
解题报告:
根据期望的线性性,可以转化成每条边被走过的次数的和。也就是:每条边的概率乘以该边的边权,求和就是答案。
AC代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define F first
#define S second
#define ll long long
#define pb push_back
#define pm make_pair
using namespace std;
typedef pair<int,int> PII;
const int MAX = 2e5 + 5;
int head[MAX],n,m,tot,in[MAX],out[MAX];
double p[MAX],ans;
struct Edge {int u,v,w;int ne;
} e[MAX];
void add(int u,int v,int w) {e[++tot].u = u;e[tot].v = v;e[tot].w = w;e[tot].ne = head[u];head[u] = tot;
}
int main()
{tot=0;memset(head,-1,sizeof head);cin>>n>>m;for(int a,b,c,i = 1; i<=m; i++) scanf("%d%d%d",&a,&b,&c),add(a,b,c),out[a]++,in[b]++; queue<int> q;q.push(1);p[1]=1;while(q.size()) {int cur = q.front();q.pop();for(int i = head[cur]; ~i; i = e[i].ne) {int v = e[i].v,u = e[i].u;in[v]--;if(!in[v]) q.push(v);p[v] += p[u]/out[u];ans += (p[u]/out[u]) * e[i].w;}}printf("%.2f\n",ans);return 0 ;
}
总结:
当然这题也可以像【POJ - 2096】Collecting Bugs(概率dp)这题一样用dp[i]代表从i这个点开始走到n号节点的平均边数,然后dp[n]=0,dp[1]就是答案。
但是这题没必要,因为那道题是:转化成DAG图之后,你知道每条边转化的概率,所以可以直接dp,但是这题你刚开始并不知道每条边被走过的概率是多少,比如这个图就不知道这一点没所以没法用这个信息。
所以这题如果非要用这种方法解题,那首先先预处理出来每条边的概率
,然后就可以用那种dp的方式求解了。