2488 绿豆蛙的归宿
提交次数:2
难度:提高-
涉及知识:拓扑排序/期望
oj:codevs
随着新版百度空间的上线,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
代码:
1 #include<iostream>
2 #include<vector>
3 #include<queue>
4 #include<cstdio>
5 using namespace std;
6 struct edge{
7 int u, w;
8 edge(int uu, int ww):u(uu), w(ww){}
9 };
10 vector<vector<edge> >v(100005);
11 queue<int>q;
12 int in[100005]; //每个点的入度
13 double p[100005]; //走到每个点的概率 Possibility
14 int n, m;
15 double ans;
16
17 int main(){
18 int i;
19 cin>>n>>m;
20 for(i = 1; i <= m; i++){
21 int a, b, c;
22 cin>>a>>b>>c;
23 v[a].push_back(edge(b, c));
24 in[b]++;
25 }
26 q.push(1);
27 p[1] = 1;
28 while(!q.empty()){
29 int node = q.front();
30 q.pop();
31 if(node == n) break;
32 for(i = 0; i < v[node].size(); i++){
33 int s = v[node].size();
34 edge next = v[node][i];
35 double k= double(p[node])/double(s);
36 p[next.u] += k;
37 in[next.u]--;
38 ans += double(next.w)*k;
39 if(in[next.u]==0){
40 q.push(next.u);
41 }
42 }
43 }
44 printf("%.2lf\n",ans);
45 return 0;
46 }
备注:
昨天上课时说到拓扑排序,老师随手在codevs上按题目分类搜的题(反正一共就两道),一道裸的拓扑排序。难点在于。。期望orz 最开始对这道题要求的期望完全理解错了
第一次提交忘了改输出格式是输出两位小数。
注意标黄的几行,改了好几次才改对,逻辑没弄清楚,现在梳理一下。
扩展到一个点后计算到达这个点的概率p[i],方法是这个点原本的概率(因为也可能在之前从别的点扩展到它)+走到上一个点的概率p[node]/上一个点的出度,这时因为已经开始删边了,相当于已经走了那几条边,所以要算对ans的贡献,怎么算呢?
边长*(走到上一个点的概率/上一个点的出度),这块似乎有点绕,但其实也很显然。走这条边的概率和走到这条边连的下一个点的概率没有直接关系(原因同上,点的概率要累加)
这样看似乎就是一道很简单的题。。。以后要先想清楚再写,写完再改又废时间又有风险。。