题目链接
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;
}
标签:217,归宿,idx,int,绿豆蛙,long,le,define
From: https://www.cnblogs.com/zyyun/p/16954376.html