算法与数据结构---8.1、过河卒-搜索解法
一、总结
一句话总结:
过河卒搜索的解法可以先思考没有马的简单情况,有马的情况,只是递归的终止条件从起点变成了起点或者马控制的区域
#include <iostream> #include <cstring> using namespace std; int hx[9]={0,-2,-1,1,2,2,1,-1,-2}; int hy[9]={0,1,2,2,1,-1,-2,-2,-1}; long long f[25][25]; long long find(int x,int y){ //如果缓存里面有,就从缓存里面拿 //否则计算结果存入缓存 if(f[x][y]!=-1) return f[x][y]; else{ //f[i][j]=f[i-1][j]+f[i][j-1] if(x-1>=0&&y-1>=0) return f[x][y]=find(x-1,y)+find(x,y-1); else if(x-1>=0) return f[x][y]=find(x-1,y); else if(y-1>=0) return f[x][y]=find(x,y-1); else return f[x][y]=0; } } int main(){ int bx,by,mx,my; cin>>bx>>by>>mx>>my; memset(f,-1,sizeof(f)); f[0][0]=1; //将马控制的点加入到f数组 for(int i=0;i<=8;i++){ int now_x=mx+hx[i]; int now_y=my+hy[i]; if(now_x>=0&&now_y>=0){ f[now_x][now_y]=0; } } cout<<find(bx,by)<<endl; return 0; }
1、过河卒的搜索解法的注意点?
1、本题(过河卒)的路径条数是超过int的,所以要用long long
2、使用递推表达式f[i][j]=f[i-1][j]+f[i][j-1]时,因为有i-1、j-1,所以要考虑i、j是否大于1的情况
3、初始化的时候,不能直接初始化i=0和j=0对应的两条线,因为当马的控制点在这两条线上时,控制点后的点是达不到的
二、过河卒
1、题目描述
/* 题目位置: P1002 过河卒 - 洛谷 https://www.luogu.com.cn/problem/P1002 */ /* 样例输入:6 6 3 3 样例输出:6 b点是(6,6),马的坐标是(3,3) A是A点 , B是B点, M是马的位置, X是被马拦着不能走的点 A 0 0 0 0 0 0 0 0 X 0 X 0 0 0 X 0 0 0 X 0 0 0 0 M 0 0 0 0 X 0 0 0 X 0 0 0 X 0 X 0 0 0 0 0 0 0 0 B 其中每个点的值代表的是当前这个点会有几条路径用过这个点 (路径指的是从A到B的路径) 1 1 1 1 1 1 1 1 2 X 1 X 1 2 1 X 0 1 1 X 2 1 1 1 M 1 1 3 1 X 1 1 0 X 3 1 1 X 1 X 0 3 1 2 2 3 3 3 6 */
2、搜索解法
博客对应课程的视频位置:8.1、过河卒-搜索解法
https://www.fanrenyi.com/video/27/288
1 /* 2 3 递推表达式: 4 卒子可以向下走和向右走 5 如果设f[i][j]表示走到(i,j)点的路径总数 6 对应的走到f[i][j]只能从上边来或者从左边来 7 f[i][j]=f[i-1][j]+f[i][j-1] 8 9 10 简单的思考: 11 如果没有这个马,搜索应该怎么做 12 13 递归: 14 递归的终止条件:起点 15 递归的递推表达式:f[i][j]=f[i-1][j]+f[i][j-1] 16 递归的返回值:路径条数 17 18 初始值:f[0][0]=1 19 20 如果有马的情况 21 递归的终止条件:起点或者马控制的区域 22 23 24 注意: 25 1、本题的路径条数是超过int的,所以要用long long 26 2、使用递推表达式f[i][j]=f[i-1][j]+f[i][j-1]时, 27 因为有i-1、j-1,所以要考虑i、j是否大于1的情况 28 3、初始化的时候,不能直接初始化i=0和j=0对应的两条线, 29 因为当马的控制点在这两条线上时,控制点后的点是达不到的 30 31 32 思考: 33 1 1 1 1 1 1 1 34 1 2 X 1 X 1 2 35 1 X 0 1 1 X 2 36 1 1 1 M 1 1 3 37 1 X 1 1 0 X 3 38 1 1 X 1 X 0 3 39 1 2 2 3 3 3 6 40 这里初始化的时候能直接初始化i=0和j=0对应的两条线么 41 不能,因为如果这样初始化后,当马的位置如果是(4,0), 42 那么(5,0)的位置本来是去不了的, 43 但是这样初始化却会初始化为1 44 45 46 */ 47 #include <iostream> 48 #include <cstring> 49 using namespace std; 50 int hx[9]={0,-2,-1,1,2,2,1,-1,-2}; 51 int hy[9]={0,1,2,2,1,-1,-2,-2,-1}; 52 long long f[25][25]; 53 long long find(int x,int y){ 54 //如果缓存里面有,就从缓存里面拿 55 //否则计算结果存入缓存 56 if(f[x][y]!=-1) return f[x][y]; 57 else{ 58 //f[i][j]=f[i-1][j]+f[i][j-1] 59 if(x-1>=0&&y-1>=0) return f[x][y]=find(x-1,y)+find(x,y-1); 60 else if(x-1>=0) return f[x][y]=find(x-1,y); 61 else if(y-1>=0) return f[x][y]=find(x,y-1); 62 else return f[x][y]=0; 63 } 64 } 65 66 int main(){ 67 int bx,by,mx,my; 68 cin>>bx>>by>>mx>>my; 69 memset(f,-1,sizeof(f)); 70 f[0][0]=1; 71 72 //将马控制的点加入到f数组 73 for(int i=0;i<=8;i++){ 74 int now_x=mx+hx[i]; 75 int now_y=my+hy[i]; 76 if(now_x>=0&&now_y>=0){ 77 f[now_x][now_y]=0; 78 } 79 } 80 81 cout<<find(bx,by)<<endl; 82 return 0; 83 }