【BZOJ 1415】 1415: [Noi2005]聪聪和可可 (bfs+记忆化搜索+期望)

1415: [Noi2005]聪聪和可可

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 1640  Solved: 962

Description

Input

数据的第1行为两个整数N和E,以空格分隔,分别表示森林中的景点数和连接相邻景点的路的条数。 第2行包含两个整数C和M,以空格分隔,分别表示初始时聪聪和可可所在的景点的编号。 接下来E行,每行两个整数,第i+2行的两个整数Ai和Bi表示景点Ai和景点Bi之间有一条路。 所有的路都是无向的,即:如果能从A走到B,就可以从B走到A。 输入保证任何两个景点之间不会有多于一条路直接相连,且聪聪和可可之间必有路直接或间接的相连。

Output

输出1个实数,四舍五入保留三位小数,表示平均多少个时间单位后聪聪会把可可吃掉。

Sample Input

【输入样例1】

4 3

1 4

1 2

2 3

3 4

【输入样例2】

9 9

9 3

1 2

2 3

3 4

4 5

3 6

4 6

4 7

7 8

8 9

Sample Output

【输出样例1】

1.500

【输出样例2】

2.167

HINT

【样例说明1】
开始时,聪聪和可可分别在景点1和景点4。
第一个时刻,聪聪先走,她向更靠近可可(景点4)的景点走动,走到景点2,然后走到景点3;假定忽略走路所花时间。
可可后走,有两种可能:
第一种是走到景点3,这样聪聪和可可到达同一个景点,可可被吃掉,步数为1,概率为 。
第二种是停在景点4,不被吃掉。概率为 。
到第二个时刻,聪聪向更靠近可可(景点4)的景点走动,只需要走一步即和可可在同一景点。因此这种情况下聪聪会在两步吃掉可可。
所以平均的步数是1* +2* =1.5步。

对于所有的数据,1≤N,E≤1000。
对于50%的数据,1≤N≤50。

Source

【分析】

  先n次bfs求出聪聪会走哪里。

  然后直接记忆化搜索求期望就好了。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<queue>
 7 using namespace std;
 8 #define Maxn 1010
 9 #define Maxm 1010
10
11 int mymin(int x,int y) {return x<y?x:y;}
12
13 struct node
14 {
15     int x,y,next;
16 }t[Maxm*2];
17 int first[Maxn],len;
18 int d[Maxn];
19
20 void ins(int x,int y)
21 {
22     t[++len].x=x;t[len].y=y;
23     t[len].next=first[x];first[x]=len;
24     d[x]++;
25 }
26
27 int n,m;
28 int dis[Maxn][Maxn],pre[Maxn],wk[Maxn][Maxn];
29 queue<int > q;
30 void bfs(int nw)
31 {
32     for(int i=1;i<=n;i++) dis[nw][i]=-1;
33     while(!q.empty()) q.pop();
34     dis[nw][nw]=0;q.push(nw);
35     while(!q.empty())
36     {
37         int x=q.front();q.pop();
38         for(int i=first[x];i;i=t[i].next)
39         {
40             int y=t[i].y;
41             if(dis[nw][y]!=-1&&dis[nw][x]+1==dis[nw][y]) pre[y]=mymin(pre[y],x);
42             else if(dis[nw][y]==-1)
43             {
44                 dis[nw][y]=dis[nw][x]+1;
45                 pre[y]=x;
46                 q.push(y);
47             }
48         }
49     }
50     for(int i=1;i<=n;i++) wk[i][nw]=pre[i];
51 }
52
53 double f[Maxn][Maxn];
54 bool vis[Maxn][Maxn];
55
56 double ffind(int st,int ed)
57 {
58     if(st==ed) return f[st][ed]=0;
59     if(dis[st][ed]<=2) return f[st][ed]=1.0;
60     if(vis[st][ed]) return f[st][ed];
61     f[st][ed]=0;vis[st][ed]=1;
62     int to=wk[wk[st][ed]][ed];
63     for(int i=first[ed];i;i=t[i].next)
64     {
65         int y=t[i].y;
66         f[st][ed]+=(ffind(to,y)+1)*1.0/(d[ed]+1);
67     }
68     f[st][ed]+=(ffind(to,ed)+1)*1.0/(d[ed]+1);
69     return f[st][ed];
70 }
71
72 int main()
73 {
74     int st,ed;
75     scanf("%d%d%d%d",&n,&m,&st,&ed);
76     len=0;
77     memset(first,0,sizeof(first));
78     for(int i=1;i<=m;i++)
79     {
80         int x,y;
81         scanf("%d%d",&x,&y);
82         ins(x,y);ins(y,x);
83     }
84     for(int i=1;i<=n;i++) bfs(i);
85     memset(vis,0,sizeof(vis));
86     ffind(st,ed);
87     printf("%.3lf\n",f[st][ed]);
88     return 0;
89 }

2017-04-22 08:51:55

时间: 2024-10-09 07:16:38

【BZOJ 1415】 1415: [Noi2005]聪聪和可可 (bfs+记忆化搜索+期望)的相关文章

bzoj 1638: [Usaco2007 Mar]Cow Traffic 奶牛交通【记忆化搜索】

震惊!记忆化搜索忘记返回map值调了半小时! 边(u,v)的经过次数是:能到u的牛数*v到n的方案数.正反两次连边,dfs两次即可 #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=5005,M=50005; int n,m,x[M],y[M],h[N],cnt,ans,f[N],g[N]; struct qwe { int ne,to; }e[M

[BZOJ 1055] [HAOI2008] 玩具取名 【记忆化搜索】

题目链接:BZOJ - 1055 题目分析 这种类似区间 DP 的记忆化搜索都是很相近的,比如字符串压缩和字符串扩展都差不多. 都是将现在 Solve 的区间分成子区间,再求解子区间. 这道题 Solve(l, r, x) 求能否将 [l, r] 的区间还原成 x ,那么就将它分成两段,看是否能左段变成 p , 右段变成 q. (x 能变成 pq) 代码 #include <iostream> #include <cstdio> #include <cstdlib> #

BZOJ 1415 NOI2005 聪聪和可可 期望DP+记忆化搜索 BZOJ200题达成&amp;&amp;NOI2005全AC达成

题目大意:给定一个无向图,聪聪在起点,可可在终点,每个时刻聪聪会沿最短路走向可可两步(如果有多条最短路走编号最小的点),然后可可会等概率向周围走或不动,求平均多少个时刻后聪聪和可可相遇 今天早上起床发现194了然后就各种刷--当我发现199的时候我决定把第200题交给05年NOI仅剩的一道题--结果尼玛调了能有一个小时--我居然没看到编号最小这个限制0.0 首先我们知道,由于聪聪走两步而可可走一步,所以聪聪一定能在有限的时刻追上可可,而且两人的距离随着时间进行单调递减 于是我们记忆化搜索 首先用

BZOJ 1415 【NOI2005】 聪聪和可可

题目链接:聪聪和可可 一道水题--开始还看错题了,以为边带权--强行\( O(n^3)\)预处理-- 首先,我们显然可以预处理出一个数组\( p[u][v] \)表示可可在点\(u\),聪聪在点\(v\)的时候聪聪下一步会往哪里走.然后--一个记忆化搜索就轻易地解决掉了-- 至于转移方程吗,我觉得也没有必要写了--你要是实在不知道就看一看代码吧-- 下面贴代码: #include<iostream> #include<cstdio> #include<cstring>

【bzoj1415】[Noi2005]聪聪和可可 期望记忆化搜索

题目描述 输入 数据的第1行为两个整数N和E,以空格分隔,分别表示森林中的景点数和连接相邻景点的路的条数. 第2行包含两个整数C和M,以空格分隔,分别表示初始时聪聪和可可所在的景点的编号. 接下来E行,每行两个整数,第i+2行的两个整数Ai和Bi表示景点Ai和景点Bi之间有一条路. 所有的路都是无向的,即:如果能从A走到B,就可以从B走到A. 输入保证任何两个景点之间不会有多于一条路直接相连,且聪聪和可可之间必有路直接或间接的相连. 输出 输出1个实数,四舍五入保留三位小数,表示平均多少个时间单

[BZOJ 1048] [HAOI2007] 分割矩阵 【记忆化搜索】

题目链接:BZOJ - 1048 题目分析 感觉这种分割矩阵之类的题目很多都是这样子的. 方差中用到的平均数是可以直接算出来的,然后记忆化搜索 Solve(x, xx, y, yy, k) 表示横坐标范围 [x, xx], 纵坐标范围 [y, yy] 的矩阵切成 k 块的最小 sigma((Vi - Ave)^2) . 然后再递归将矩阵分得更小,直到 k 为 1 的时候直接返回相应的值. 代码 #include <iostream> #include <cstdlib> #incl

Vijos1675 NOI2005 聪聪和可可 记忆化搜索

简单题,结果因为理解错题意懵逼了好久…… moveTo[x][y]表示聪聪在节点x,可可在节点y时,聪聪下一步应到达哪一个节点 dp[x][y]表示聪聪在节点x,可可在节点y,且轮到可可行动时,所需时间的数学期望(可可第一次行动不计入其内) 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <vector> 5 #include <queue> 6

【BZOJ1415】【Noi2005】聪聪和可可 概率DP 记忆化搜索

链接: #include <stdio.h> int main() { puts("转载请注明出处[辗转山河弋流歌 by 空灰冰魂]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/46457811"); } 题解: 记忆化搜索. f(i,j) 表示猫在 i .鼠在 j 时的期望. 然后显然它是拓扑的,然后先枚举起点n遍bfs算出 f(i,j) 时猫只走一步应该到哪个节点,然后对于 f(i,j) 枚

bzoj 1415 期望+记忆化搜索 ****

1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<map> 8 using namespace std; 9 #define MOD 1000000007 10 const int INF=0x3f3f3f3f; 11