具体思路:
DP或者深搜+备忘录;
1.记忆搜索:
普通搜索会爆栈,所以只能采用记忆化搜索;
例如,如果走到i,j的位置,之前如果搜索到该位置,直接读取相应的值,不用继续搜索;
但是有两大问题:
1.对于相同位置,如果所剩步数不同,则必定会导致结果不同,所以针对于每个位置,应该有不同剩余步数的记录;
2.对于该搜索问题,只能自底向上,因此只能采用递归思路,即从子节点开始进行;
对于返回值,应该对每个方向的返回概率的加和,整体除以8,作为当前剩余步数k的[i,j]节点的可能剩余步数;
2.DP思路:
DP思路和搜索思路有点像,但是唯一要注意的是,可以从0步构建每个坐标的状态转移方程,这样更方便一些;
具体代码:
记忆搜索:
class Solution {
public:
vector<vector<int>>dir{{1,2},{2,1},{-1,2},{2,-1},{1,-2},{-1,-2},{-2,1},{-2,-1}};
map<int,map<int,double>>record;
double knightProbability(int n, int k, int row, int column) {
if(k==0)
return 1;
if(record[row*n+column].find(k)!=record[row*n+column].end()){
//当找到记录时;
return record[row*n+column][k];
}
double pro=0.0;
for(int i=0;i<dir.size();i++){
int nx=dir[i][0]+row;
int ny=dir[i][1]+column;
if(nx>=0&&nx<n&&ny>=0&&ny<n)
pro+= knightProbability(n,k-1,nx,ny)/8;
}
record[row*n+column][k]=pro;
return pro;
}
};
DP思路:
class Solution {
public:
vector<vector<int>>dir{{1,2},{2,1},{-1,2},{2,-1},{1,-2},{-1,-2},{-2,1},{-2,-1}};
double knightProbability(int n, int k, int row, int column) {
vector<vector<double>>dp(k+1,vector<double>(n*n+1,1));
for(int s=1;s<=k;s++){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
double pro=0;
for(int kk=0;kk<dir.size();kk++) {
int nx=i+dir[kk][0];
int ny=j+dir[kk][1];
if(nx>=0&&ny>=0&&nx<n&&ny<n){
pro+=dp[s-1][nx*n+ny]/8;
}
}
dp[s][i*n+j]=pro;
}
}
}
return dp[k][row*n+column];
}
};