【NOI2005】 聪聪与可可

题目描述
聪聪与可可
主文件名:cchkk
【问题描述】
在一个魔法森林里,住着一只聪明的小猫聪聪和一只可爱的小老鼠可可。虽
然灰姑娘非常喜欢她们俩,但是,聪聪终究是一只猫,而可可终究是一只老鼠,
同样不变的是,聪聪成天想着要吃掉可可。
一天,聪聪意外得到了一台非常有用的机器,据说是叫 GPS,对可可能准确
的定位。
有了这台机器,聪聪要吃可可就易如反掌了。
于是,聪聪准备马上出发,去找可可。而可怜的可可还不知道大难即将临头,仍在森林里无忧无虑的玩耍。小兔子乖乖听到这件事,马上向灰姑娘报告。灰姑娘决定尽快阻止聪聪,拯救可可,可她不知道还有没有足够的时间。
整个森林可以认为是一个无向图,图中有 N 个美丽的景点,景点从 1 至 N
编号。小动物们都只在景点休息、玩耍。在景点之间有一些路连接。
当聪聪得到 GPS 时,可可正在景点 M(M≤N)处。以后的每个时间单位,可可
都会选择去相邻的景点(可能有多个)中的一个或停留在原景点不动。而去这些地
方所发生的概率是相等的。假设有 P 个景点与景点 M 相邻,它们分别是景点 R、
1
景点 S,......景点 Q,在时刻 T 可可处在景点 M,则在(T+1)时刻,可可有1/(P +1)
的可能在景点 R,有1/(P+1)的可能在景点 S,......,有1/(P +1)
的可能在景点 Q,还有1/(P +1)的可能停在景点 M。
我们知道,聪聪是很聪明的,所以,当她在景点 C 时,她会选一个更靠近
可可的景点,如果这样的景点有多个,她会选一个标号最小的景点。由于聪聪太
想吃掉可可了,
如果走完第一步以后仍然没吃到可可,她还可以在本段时间内再向可可走近一步。
在每个时间单位,假设聪聪先走,可可后走。在某一时刻,若聪聪和可可位
于同一个景点,则可怜的可可就被吃掉了。
灰姑娘想知道,平均情况下,聪聪几步就可能吃到可可。而你需要帮助灰姑
娘尽快的找到答案。
【输入格式】
从文件 cchkk.in 中读入数据。
数据的第 1 行为两个整数 N 和 E,以空格分隔,分别表示森林中的景点数和
连接相邻景点的路的条数。
第 2 行包含两个整数 C 和 M,以空格分隔,分别表示初始时聪聪和可可所在
的景点的编号。
接下来 E 行,每行两个整数,第 i+2 行的两个整数 Ai 和 Bi 表示景点 Ai 和景
点 Bi 之间有一条路。
所有的路都是无向的,即:如果能从 A 走到 B,就可以从 B 走到 A。
输入保证任何两个景点之间不会有多于一条路直接相连,且聪聪和可可之间
必有路直接或间接的相连。
【输出格式】
输出到文件 cchkk.out 中。
输出 1 个实数,四舍五入保留三位小数,表示平均多少个时间单位后聪聪会
把可可吃掉。
【输入样例 143
14
12
23
34
【输出样例 11.500
【样例说明 1】
开始时,聪聪和可可分别在景点 1 和景点 4。
第一个时刻,聪聪先走,她向更靠近可可(景点 4)的景点走动,走到景点 2,
然后走到景点 3;假定忽略走路所花时间。
可可后走,有两种可能:
第一种是走到景点 3,这样聪聪和可可到达同一个景点,可可被吃掉,步数
为 1,概率为 1/2。
到第二个时刻,聪聪向更靠近可可(景点 4)的景点走动,只需要走一步即和
可可在同一景点。因此这种情况下聪聪会在两步吃掉可可。
所以平均的步数是 1* 1/2+2*1/2 =1.5 步。
第二种是停在景点 4,不被吃掉。概率为
【输入样例 299
93
12
23
34
45
36
46
47
78
89
【输出样例 22.167
【样例说明 2】
森林如下图所示:

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

 

题解

 

解法1:搜索
 1 (*
 2     *Problem:    NOI2005 聪聪与可可
 3     *Author :    Chen Yang
 4     *Time   :    2012.6.5 9:00 am
 5     *State  :    50分
 6     *Memo   :    搜索
 7 *)
 8 program cchkk;
 9 const zero=1e-8;
10 var
11   n,m,c,e,i,j,k:longint;
12   ans:extended;
13   d:array[0..1000,0..1000] of longint;
14   sum:array[0..1000] of longint;
15 //======================
16 procedure find(s,t,time:longint; p:extended);
17 var
18   i,j,dis,k,q:longint;
19 begin
20   //writeln(s,' ',t,' ',time,' ',p:0:3);
21   if s=t then
22   begin
23     ans:=ans+p*time;
24     exit;
25   end;
26   if p<zero then exit;
27   dis:=maxlongint; k:=0;
28   for j:=1 to n do
29   if (d[j,s]<dis)and(d[t,j]=1) then
30   begin
31     dis:=d[j,s]; k:=j;
32   end;
33   if k=0 then exit;
34   if k=s then
35   begin
36     find(s,k,time+1,p);
37     exit;
38   end;
39   dis:=maxlongint; q:=0;
40   for j:=1 to n do
41   if (d[j,s]<dis)and(d[k,j]=1) then
42   begin
43     dis:=d[j,s]; q:=j;
44   end;
45   if q=s then
46   begin
47     find(s,q,time+1,p);
48     exit;
49   end;
50   for i:=1 to n do
51   if (d[s,i]=1)or(i=s) then find(i,q,time+1,p/sum[s]);
52 end;
53 //======================
54 begin
55   assign(input,'cchkk.in'); reset(input);
56   assign(output,'cchkk.out'); rewrite(output);
57   read(n,e); read(c,m);
58   fillchar(d,sizeof(d),$7);
59   for i:=1 to n do sum[i]:=1;
60   for i:=1 to e do
61   begin
62     read(j,k);
63     d[j,k]:=1; d[k,j]:=1;
64     inc(sum[k]); inc(sum[j]);
65   end;
66   for i:=1 to n do d[i,i]:=0;
67   for k:=1 to n do
68   for i:=1 to n do
69   if i<>k then
70   for j:=1 to n do
71   if (j<>k)and(j<>i)and(d[i,j]>d[i,k]+d[k,j]) then
72   d[i,j]:=d[i,k]+d[k,j];
73   find(m,c,0,1);
74   writeln(ans:0:3);
75   close(input); close(output);
76 end.

 

解法2:记忆化搜索
 1 /*
 2     *Problem:    NOI2005 聪聪与可可
 3     *Author :    Chen Yang
 4     *Time   :    2012.6.5 4:00 pm
 5     *State  :    Solved
 6     *Memo   :    记忆化搜索
 7 */
 8 #include <cstdio>
 9 #include <cstdlib>
10 #include <cstring>
11 #include <string>
12 #include <algorithm>
13 using namespace std;
14 typedef long double LD;
15 const int maxn = 1010; 
16 const LD zero=1e-6;
17 int n, m, s, t, P[maxn][maxn], dui[maxn], dis[maxn], cnt[maxn];
18 LD f[maxn][maxn];
19 bool get[maxn];
20 struct edge
21 {
22     int x; edge *next; edge() {}
23     edge(int x, edge* next): x(x), next(next) {}
24 } *first[maxn];
25 
26 void spfa(int s)
27 {
28     memset(get, 0, sizeof get);
29     memset(dis, 0x7, sizeof dis);
30     dui[1] = s; dis[s] = 0; ++cnt[s]; P[s][s] = s;
31     for (int l=0, r=1; l<r;)
32     {
33         int x = dui[++l]; get[x] = 0;
34         for (edge* p=first[x]; p; p=p->next)
35         {
36             if (dis[p->x]>dis[x]+1 || (dis[p->x]==dis[x]+1 && x<P[p->x][s]))
37             {
38                 dis[p->x] = dis[x]+1, P[p->x][s] = x;
39                 if (!get[p->x]) get[p->x] = 1, dui[++r] = p->x;
40             }
41         }
42     }
43 }
44 
45 LD dp(int x, int y)
46 {
47     if (x == y) return 0;
48     if (f[x][y]>zero) return f[x][y];
49     int j = P[x][y];
50     if (j == y) return f[x][y] = 1;
51     j = P[j][y];
52     if (j == y) return f[x][y] = 1;
53     f[x][y] = dp(j,y);
54     for (edge* p=first[y]; p; p=p->next) f[x][y] += dp(j,p->x);
55     return f[x][y] = f[x][y]/cnt[y] + 1;    
56 }
57 
58 int main()
59 {
60     freopen("cchkk.in", "r", stdin);
61     freopen("cchkk.out", "w", stdout);
62     memset(P, 0x7, sizeof P);
63     scanf("%d%d%d%d", &n, &m, &s, &t);
64     for (int i=1, x, y; i<m+1; ++i)
65         scanf("%d%d", &x, &y),
66         first[x] = new edge(y, first[x]),
67         first[y] = new edge(x, first[y]),
68         ++cnt[x], ++cnt[y];
69     for (int i=1; i<n+1; ++i) spfa(i);
70     printf("%.3Lf\n", dp(s,t));
71     return 0;
72 }

 

posted @ 2012-06-06 17:05  datam  阅读(622)  评论(1编辑  收藏  举报