【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 个实数,四舍五入保留三位小数,表示平均多少个时间单位后聪聪会 把可可吃掉。 【输入样例 1】 43 14 12 23 34 【输出样例 1】 1.500 【样例说明 1】 开始时,聪聪和可可分别在景点 1 和景点 4。 第一个时刻,聪聪先走,她向更靠近可可(景点 4)的景点走动,走到景点 2, 然后走到景点 3;假定忽略走路所花时间。 可可后走,有两种可能: 第一种是走到景点 3,这样聪聪和可可到达同一个景点,可可被吃掉,步数 为 1,概率为 1/2。 到第二个时刻,聪聪向更靠近可可(景点 4)的景点走动,只需要走一步即和 可可在同一景点。因此这种情况下聪聪会在两步吃掉可可。 所以平均的步数是 1* 1/2+2*1/2 =1.5 步。 第二种是停在景点 4,不被吃掉。概率为 【输入样例 2】 99 93 12 23 34 45 36 46 47 78 89 【输出样例 2】 2.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 }