我的第一篇文章(刷题记录)

大意:士兵想要过河,他每一次可以往下走一格,也可以往右走一格,但马一步走到的地方是不能走的,问走到nnn行,mmm列有多少种走法

注释:对于 100% 的数据,1≤n,m≤20,0≤ 马的坐标 ≤20   //给的数据虽小,但计算结果一点都不小会爆int,永远不要小看指数爆炸。

我们都知道马走日,马能到达的地方如下

 在知道马能到达的地方,我们有一种解题思路把马能到达的地方做一个标记。

具体做法:我们把坐标系用表格代替,把用一个二维数组存放表格的内容,能经过的地方都设置为0,马能到达的即为不能经过的地方设置为1,。在走下一步的时候作一个判断即可

void sett(int x,int y){
    ma[x][y]=1;
    ma[x-1][y-2]=1;
    ma[x-2][y-1]=1;
    ma[x-2][y+1]=1;
    ma[x-1][y+2]=1;
    ma[x+1][y-2]=1;
    ma[x+2][y-1]=1;
    ma[x+2][y+1]=1;
    ma[x+1][y+2]=1;
}//看不明白参考上图

对于这个问题我们可以使用奥数中的一种简单而常用的方法——标数法(很显然废物的我根本不知道,你不知道也没关系,咱们现学现用。)

什么是标数法:举个简单的例子

从这个表格的第一行第一列,走到第二行第二列的走法数量是由走到第一行第二列的方案数+第二行第一列的方案数,也就是走到x行,y列的方案数=走到x-1行,y列的方案数+走到x行,y-1列的方案数(出界就按0算)

f[i][j] = f[i-1][j]+f[i][j-1]

因为走到x行y列的方案显然是来自于它的左边和它的上面,因为只有这两个格子才可以一步到达这个格子。

于是我们就可以开始递推

for(int i=1;i<=n;i++){
    for(int j=1;j<=m;j++){
      	if(i==1&&j==1)continue;
       	if(ma[i][j]==0)x[i][j]=x[i-1][j]+x[i][j-1];
    }
}

 完整代码如下:

#include <bits/stdc++.h>
using namespace std;
long long a,b,n,m,x[23][23],ma[23][23];
void sett(long long x,int y){//定义一个函数标记马能到达的地方;
    ma[x][y]=1;
    ma[x-1][y-2]=1;
    ma[x-2][y-1]=1;
    ma[x-2][y+1]=1;
    ma[x-1][y+2]=1;
    ma[x+1][y-2]=1;
    ma[x+2][y-1]=1;
    ma[x+2][y+1]=1;
    ma[x+1][y+2]=1;
}
int main(){
    scanf("%lld %lld %lld %lld",&n,&m,&a,&b);
    a++;     //因为我们是抽象成表格来做的,表格没有x和y轴,所以加1;
    b++;
    n++;
    m++;
    sett(a,b);
    x[1][1]=1;   //初始化(0 ,0)位置的值;
    for(int i=1;i<=n;i++){//暴力枚举--还好数据不是特别的
        for(int j=1;j<=m;j++){
        	if(i==1&&j==1)continue;//排除去初始位置
        	if(ma[i][j]==0)//判断能否经过
            x[i][j]=x[i-1][j]+x[i][j-1];
        }
    }
    printf("%lld",x[n][m]);
    return 0;
}

 其实我们还可以进一步优化:

  观看这张图,我们还可以发现其他的东西,我们能发现下面一行比上一行大的值,就是它左边格   子的值,所以,我们可以将这道题优化成一维,代码实现也是很简单的。 

f[i]+=f[i-1]

进一步优化代码如下:

待续。。。。。       莫慌过两天就搞好了。

其他方法:

待续。。。。。

---------等到有一天学到更好的方法再来补充。

到此我的第一篇文章收尾。

--------如有错误请指出

--------文笔不好请勿介意

--------新人求点赞关注

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值