Luogu P4316 绿豆蛙的归宿
Luogu P4316 绿豆蛙的归宿
题目大意:
给定一个 DAG,求起点到终点的路径长度的期望。
貌似是这种概率题的一种套路,逆推。
我们设从起点到终点的路径上 \(f[i]\) 表示 \(i\) 点到达终点的期望路径长度,那么我们前一点总是可以由后一点的 \(f\) 状态推导而来。
所以我们可以得到: $$f[i] = \frac{\sum\limits_{i \to j} f[j] + w}{out[i]}$$
所以我们可以反向建边,拓扑,然后初始化 \(f[n] = 0\),输出 \(f[1]\) 即可。
代码:
using namespace std;
const int N = 1e5 + 5;
int n, m, cnt, head[N], in[N], deg[N];
double f[N];
struct Edge {
int to, next;
double w;
}e[N << 1];
inline int read() {
int x = 0, f = 1;
char c = getchar();
while (!isdigit(c)) {
if (c == '-') f = -1;
c = getchar();
}
while (isdigit(c)) x = x * 10 + c - '0', c = getchar();
return x * f;
}
inline void add(int x, int y, double z) {
e[++cnt].to = y;
e[cnt].next = head[x];
e[cnt].w = z;
head[x] = cnt;
}
int main() {
n = read(), m = read();
int x, y;
double z;
for (int i = 1; i <= m; ++i) {
x = read(), y = read();
scanf("%lf", &z);
add(y, x, z);
++in[x], ++deg[x];
}
f[n] = 0.0;
queue <int> q;
q.push(n);
while (!q.empty()) {
int top = q.front();
q.pop();
int to;
for (int i = head[top]; i ; i = e[i].next) {
to = e[i].to;
f[to] = f[to] + (f[top] + e[i].w) / deg[to];
if (--in[to] == 0) q.push(to);
}
}
printf("%.2lf\n", f[1]);
return 0;
}