217. 绿豆蛙的归宿

题目链接

217. 绿豆蛙的归宿

给出一个有向无环的连通图,起点为 \(1\),终点为 \(N\),每条边都有一个长度。

数据保证从起点出发能够到达图中所有的点,图中所有的点也都能够到达终点。

绿豆蛙从起点出发,走向终点。

到达每一个顶点时,如果有 \(K\) 条离开该点的道路,绿豆蛙可以选择任意一条道路离开该点,并且走向每条路的概率为 \(1/K\)

现在绿豆蛙想知道,从起点走到终点所经过的路径总长度的期望是多少?

输入格式

第一行: 两个整数 \(N, M\),代表图中有 \(N\) 个点、\(M\) 条边。

第二行到第 \(1+M\) 行: 每行 \(3\) 个整数 \(a, b, c\),代表从 \(a\)\(b\) 有一条长度为 \(c\) 的有向边。

输出格式

输出从起点到终点路径总长度的期望值,结果四舍五入保留两位小数。

数据范围

\(1 \le N \le 10^5\),
\(1 \le M \le 2N\)

输入样例:

4 4
1 2 1
1 3 2
2 3 3
3 4 4

输出样例:

7.00

解题思路

概率dp

状态表示:\(f[i]\) 表示 \(i\sim n\) 的期望长度
状态计算:反向建边,假设已经求得 \(f[i]\) 的期望长度,需要求解其连向边权为 \(w\)\(j\) 这个点的期望,计算一开始时 \(j\) 这个点的出边有 \(d\) 条,则对于 \(j\) 来说,\(i\)\(j\) 这条边的期望贡献为 \(\frac{f[i]+w}{d}\),按照拓扑排序更新状态即可

另外题目保证出度为 \(0\) 的点有且仅有 \(n\) 这一个点,即假设还存在一个出度为 \(0\) 的点,又由于这样的图是一个 dag,所有这样的点到达不了 \(n\),与题意矛盾,故出度为 \(0\) 的点仅有 \(n\) 这一个点

  • 时间复杂度:\(O(n+m)\)

代码

// Problem: 绿豆蛙的归宿
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/219/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

const int N=1e5+5,M=2*N;
int n,m,d[N],din[N];
int h[N],w[M],ne[M],e[M],idx;
double f[N];
bool v[N];
void add(int a,int b,int c)
{
	e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
int main()
{
	memset(h,-1,sizeof h);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
    	int x,y,z;
    	scanf("%d%d%d",&x,&y,&z);
    	d[x]++;
    	add(y,x,z);
    	din[x]++;
    }
    f[n]=0;
    queue<int> q;
    q.push(n);
    while(q.size())
    {
    	int x=q.front();
    	q.pop();
    	for(int i=h[x];~i;i=ne[i])
    	{
    		int y=e[i];
    		f[y]+=(f[x]+w[i])/d[y];
    		if(--din[y]==0)q.push(y);
    	}
    }
	printf("%.2lf",f[1]);
    return 0;
}
posted @ 2022-12-06 09:55  zyy2001  阅读(23)  评论(0编辑  收藏  举报