【无标题】

学习数据结构的第二十一天

动态规划

怎么说呢,不学不知道,一学吓一跳,真的,到时候一看出来,就只知道两个字,妙啊!
先看题目

[蓝桥杯 2020 省 AB1] 走方格

题目描述

在平面上有一些二维的点阵。

这些点的编号就像二维数组的编号一样,从上到下依次为第 1 1 1 至第 n n n 行,从左到右依次为第 1 1 1 至第 m m m 列,每一个点可以用行号和列号来表示。

现在有个人站在第 1 1 1 行第 1 1 1 列,要走到第 n n n 行第 m m m 列。只能向右或者向下走。

注意,如果行号和列数都是偶数,不能走入这一格中。

问有多少种方案。

输入格式

输入一行包含两个整数 n n n m m m

输出格式

输出一个整数,表示答案。

样例 #1

样例输入 #1

3 4

样例输出 #1

2

提示

1 ≤ n , m ≤ 30 1\le n,m\le30 1n,m30

蓝桥杯 2020 第一轮省赛 A 组 G 题(B 组 H 题)。
一看到的时候,我直接就是递归深搜。先看我递归的代码。

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
int m,n,sum;
int book[31][31];//标记
void dfs(int s,int l)
{
    if(s==n&&l==m)
    {
        sum++;
        return;
    }
     int next[2][2]={{0,1},{1,0}};//方向数组
     int ty,tx;
        for(int j=0;j<=1;j++)
        {
            ty=s+next[j][0];
            tx=l+next[j][1];//下一个位置的坐标
            if(tx<1||tx>m||ty<1||ty>n)
            {
                continue;
            }
            if(book[ty][tx]==0)//如果没走或者没障碍物,就走
            {
                book[ty][tx]=1;
                dfs(ty,tx);
                book[ty][tx]=0;//收回
            }
        }
        return;

}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1; i <= n; i++)
		for(int j = 1; j <= m; j++)
			if(i % 2 == 0 && j % 2 == 0)
				{
				    book[i][j] = 1;//标记障碍物
				}
    dfs(1,1);
    printf("%d",sum);
    return 0;
}

但是啊,你会发现一个问题,我交上去的时候超时了,这是什么原因呢?原因就在于做了多余的判断和部署。怎么理解呢?如果(2,2)这个点不能走,那么我许多次递归都要判断一次,这样就浪费时间,并且,深搜是不断实验,那么我会有多少次重复实验这个不能走的点呢?这样就相当的浪费时间。
那么接下来我觉得秒的方法我就来解释一下。如果我们现在在(3,2)这个点怎么走?是不是只能走到(3,3),如果我们在(2,3)这个点呢?这就是问题所在了,我是不是只能走到(3,3),你发现么有?当两个数之间有一个为偶数时,我们是不是只能选择把偶数加一才能走下去。有人问为什么。大哥,双偶数不能走啊。对不对?那么为双奇数时呢?是不是都可以?那么,是不是出现了一种更好的递归方式。用奇偶来判断递归。好处显而易见,不用再过多的判断是不是能递归的点,直接避开了那个方法,这简直就是太酷啦。
那么上代码。

#include<bits/stdc++.h>
using namespace std;
int sum=0;
int n,m;
void dp(int x,int y)
{
	if(x==1||y==1)
	{
		sum++;
		return;
	}
	else if(x*y%2==0)
	{
		if(x%2==0)//x为偶数的情况
		dp(x-1,y);
		else//y
		dp(x,y-1);
	}
	else
	{
		dp(x-1,y);//两种情况
		dp(x,y-1); 
	}
	return;
} 
int main()
{
	cin>>n>>m;
	dp(n,m);//采用的倒搜啊,因为不易越界
	cout<<sum;//输出
	return 0;
}
  • 17
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值