[2019南京网络赛D题]Robots

题目链接

绝望ing!!!

搞了3个小时的D,到最后也没过,吃饭的时候突然想到错了,改一改就过了Orz.

遗憾!!错在求了拓扑序,要用a[n]->a[1],结果用成了n->1。要被队友骂死了QAQ

而且样例刚好1-n是拓扑序(


题意是说,在DAG中从1到n,每次有x/(x+1)的概率到相连的点,1/(x+1)的概率原地不动,(x为相连的点的个数)。每次移动需要一天,每次移动会消耗当前天数数值那么多的能量,求到达n点的期望能量消耗。

一开始就蛮有感觉的,DAG上跑期望dp,先跑期望天数,再跑期望能量,设dp[i]为i点到n点的期望天数,则初始dp[n]=0,转移为$dp[i]=\tfrac{1}{x+1}*\sum dp[j]+\tfrac{1}{x+1}*dp[i]+1$ j->i有边。

然后再跑期望能量,dp2[i]为i到n点的期望能量,初始为dp2[n]=0,转移为$dp2[i]=\tfrac{1}{x+1}*\sum dp2[j]+\tfrac{1}{x+1}*dp2[i]+dp[i]$  j->i有边。

代码极度丑陋,望见谅。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 4e5 + 10;
 4 struct node {
 5     int s, e, next;
 6 }edge[maxn], edge2[maxn];
 7 int head[maxn], head2[maxn], len, len2;
 8 void init() {
 9     memset(head, -1, sizeof(head));
10     memset(head2, -1, sizeof(head2));
11     len = len2 = 0;
12 }
13 void add(int s, int e) {
14     edge[len].s = s;
15     edge[len].e = e;
16     edge[len].next = head[s];
17     head[s] = len++;
18 }
19 void add2(int s, int e) {
20     edge2[len2].s = s;
21     edge2[len2].e = e;
22     edge2[len2].next = head2[s];
23     head2[s] = len2++;
24 }
25 double dp[maxn], dp2[maxn];
26 int in[maxn], a[maxn], num[maxn];
27 void solve(int n) {
28     int lens = 0;
29     queue<int>q;
30     for (int i = 1; i <= n; i++)
31         if (in[i] == 0) q.push(i);
32     while (!q.empty()) {
33         int p = q.front(); q.pop();
34         a[++lens] = p;
35         for (int i = head[p]; i != -1; i = edge[i].next) {
36             int y = edge[i].e;
37             in[y]--;
38             if (in[y] == 0)
39                 q.push(y);
40         }
41     }
42 }
43 int main() {
44     int t;
45     scanf("%d", &t);
46     while (t--) {
47         int n, m, x, y;
48         scanf("%d%d", &n, &m);
49         init();
50         for (int i = 1; i <= n; i++)
51             in[i] = 0, num[i] = 0, dp2[i] = dp[i] = 0;
52         for (int i = 1; i <= m; i++)
53             scanf("%d%d", &x, &y), add(x, y), add2(y, x), in[y]++;//正向反向各存一图,正向跑拓扑,反向求期望
54         solve(n);//求拓扑序
55         dp[a[n]] = 0;
56         for (int x = n; x >= 1; x--) {//期望dp日常倒推
57             if (a[x] != n) dp[a[x]] += num[a[x]] + 1, dp[a[x]] /= num[a[x]];//num[i]为与i点相连的点数
58             num[a[x]] = 0;
59             for (int i = head2[a[x]]; i != -1; i = edge2[i].next) {
60                 int y = edge2[i].e;
61                 dp[y] += dp[a[x]];
62                 num[y]++;
63             }
64         }
65         dp2[n] = 0;
66         for (int x = n; x >= 1; x--) {
67             if (a[x] != n) dp2[a[x]] += (num[a[x]] + 1) * dp[a[x]], dp2[a[x]] /= num[a[x]];
68             for (int i = head2[a[x]]; i != -1; i = edge2[i].next) {
69                 int y = edge2[i].e;
70                 dp2[y] += dp2[a[x]];
71                 num[y]++;
72             }
73         }
74         printf("%.2lf\n", dp2[1]);
75     }
76 }

猜你喜欢

转载自www.cnblogs.com/sainsist/p/11443200.html