[2019南京网络赛D题]Robots
2019.9.2更新
第二天睡醒想了想发现好像搜一遍就可以过,赛时写的花里胡哨的还错了,太菜了QAQ
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 3e5 + 10; 5 struct node { 6 int s, e, next; 7 }edge[maxn]; 8 int head[maxn], len; 9 void init() { 10 memset(head, -1, sizeof(head)); 11 len = 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 double dp[maxn], dp2[maxn]; 20 int vis[maxn],n; 21 void dfs(int x) { 22 if (vis[x]) 23 return; 24 vis[x] = 1; 25 dp[x] = dp2[x] = 0; 26 if (x == n) 27 return; 28 int num = 0; 29 for (int i = head[x]; i != -1; i = edge[i].next) { 30 int y = edge[i].e; 31 dfs(y); 32 dp[x] += dp[y]; 33 dp2[x] += dp2[y]; 34 num++; 35 } 36 dp[x] += num + 1, dp[x] /= num; 37 dp2[x] += (num + 1)*dp[x], dp2[x] /= num; 38 } 39 int main() { 40 int t; 41 scanf("%d", &t); 42 while (t--) { 43 int m, x, y; 44 init(); 45 scanf("%d%d", &n, &m); 46 for (int i = 1; i <= m; i++) 47 scanf("%d%d", &x, &y), add(x, y); 48 memset(vis, 0, sizeof(vis)); 49 dfs(1); 50 printf("%.2f\n", dp2[1]); 51 } 52 }
原文
绝望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$ i->j有边。
然后再跑期望能量,dp2[i]为i到n点的期望能量,初始为dp2[n]=0,转移为$dp2[i]=\tfrac{1}{x+1}*\sum dp2[j]+\tfrac{1}{x+1}*dp2[i]+dp[i]$ i->j有边。
代码极度丑陋,望见谅。
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 }