骑士 概率 记忆化搜索

骑士(利用step by step解题)

题目描述

给出一个空的国际象棋棋盘(8x8方格),棋子骑士放在其中一个方格上。国际象棋骑士走一步的8个方向如下图所示:
骑士
一开始骑士所在的格子是第x行第y列。如果骑士移动n次,每次随机均匀地挑选八个方向中的一个(可能是使骑士离开棋盘的方向),求在n次跳跃后它仍然在棋盘上的概率。一旦骑士离开了棋盘,它就无法再次进入。

输入格式

多组测试数据。
第一行,一个整数G,表示有G组测试数据。 1 <= G <= 10
每组测试数据格式:
第一行,三个整数: x, y,n。 1 <= x,y <=8。 1 <=n <=100。 一开始骑士所在的格子是第x行第y列。左下角格子是(1,1)

输出格式

共G行,共G行,每行一个实数,误差不超过0.0001。

输入样例
10
1 1 2
4 4 1
2 3 10
4 3 50
3 7 1
7 1 1
8 6 2
5 8 3
7 1 4
1 3 5
输出样例
0.1875
1.0
0.0522148497402668
8.356427906809618E-7
0.75
0.375
0.359375
0.28515625
0.1533203125
0.149078369140625

解题思路

题目大意:给出骑士最开始的位置,求骑士移动n次后,仍停留在棋盘上的概率

本题是不是很像一道dfs或bfs呢!经典的题目设定我们就用经典的解法去做,本题我们用dfs深度优先搜索

但是我们要怎样深搜去求概率呢?由题可知,对于任意一步,我们都有8种跳法,经过n次跳跃之后,我们可以得到以下的搜索树:

搜索树
这些状态都可以用 d f s ( x , y , s t e p ) dfs(x,y,step) dfs(x,y,step)来表示骑士当前在(x,y),还要走step步仍留在棋盘的概率

d f s ( x , y , s t e p ) = d f s ( x + 1 , y + 2 , s t e p + 1 ) × 1 8 + d f s ( x + 2 , y + 1 , s t e p + 1 ) × 1 8 + d f s ( x + 2 , y − 1 , s t e p + 1 ) × 1 8 ⋯ dfs(x,y,step)=dfs(x+1,y+2,step+1)\times\frac{1}{8}+dfs(x+2,y+1,step+1)\times\frac{1}{8}+dfs(x+2,y-1,step+1)\times\frac{1}{8}\cdots dfs(x,y,step)=dfs(x+1,y+2,step+1)×81+dfs(x+2,y+1,step+1)×81+dfs(x+2,y1,step+1)×81

当(x,y)不在棋盘上时,这一步返回一个0,就不会计入答案。

当step=n时,且(x,y)在棋盘上,返回一个1,计入答案。

但是本题的数据范围很大,且重复的子问题很多,所以我们要用到记忆化搜索

r e c [ x ] [ y ] [ s t e p ] rec[x][y][step] rec[x][y][step]记录骑士当前在(x,y),还要走step步仍留在棋盘的概率

下一次如果碰巧遍历到这个点就可以直接返回值了。

总感觉没什么好说的,看代码注释。


代码

#include<bits/stdc++.h>

using namespace std;
int G,x,y,n;
int dx[10]={0,1,2,2,1,-1,-2,-2,-1};
int dy[10]={0,2,1,-1,-2,-2,-1,1,2};
double rec[10][10][110];
bool vis[10][10][110];

bool onboard(int x,int y)//判断是否在棋盘上 
{
	if(x<=8&&x>=1&&y<=8&&y>=1) return 1;
	else return 0;
}

double dfs(int x,int y,int step)
{
	if(onboard(x,y)==0) return 0.0;//如果不在棋盘上,那么就出局了
	if(step==0) return 1.0;//如果这n步全部跳完了,那么成功
	if(vis[x][y][step]==1) return rec[x][y][step];//记忆化
	for(int i=1;i<=8;i++)//走八个方向
		rec[x][y][step]+=(1.00/8.00)*dfs(x+dx[i],y+dy[i],step-1);//走到这一步的概率是八分之一
	vis[x][y][step]=1;
	return rec[x][y][step];
}

int main()
{
	freopen("2799.in","r",stdin);
	freopen("2799.out","w",stdout);
	cin>>G;
	for(int gr=1;gr<=G;gr++)
	{
		cin>>x>>y>>n;
		memset(vis,0,sizeof(vis));
		memset(rec,0.0,sizeof(rec));
		cout<<fixed<<setprecision(6)<<dfs(x,y,n)<<endl;
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值