洛谷P1002过河卒题解

题目传送门icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P1002

前言

什么是dp?(由AI生成)

DP是动态规划(Dynamic Programming)的缩写。动态规划是一种解决问题的算法思想,它通过将问题分解为子问题,并保存子问题的解来解决原问题。DP常用于求解具有重叠子问题和最优子结构性质的问题。

在动态规划中,使用一个状态数组或表格来保存子问题的解。通过填表或者递归的方式,逐步求解子问题,并最终得到原问题的解。动态规划具有时间和空间上的优化,可以大大减少重复计算的次数,提高算法的效率。

动态规划常用于求解最优化问题,如最长递增子序列、背包问题、最短路径等等。它在算法设计和解决实际问题中有广泛的应用。

整体思路

首先它说小兵只能向右方向和下方向移动所以举个例子(手工制作不易,敬请谅解):

这里我们可以假设画红晕的地方是不能走的,那麽我们可以发现画绿叉的地方也是不能走的。

接着我们再来看一下,假如:

1种1种1种
1种2种3种
1种3种6种

以我标红的为例:

他有一种是从上面下来(加上上面的方案数)

还有一种是从左边过来(加上左边的方案数)

由此得到最最最最最重要的:        
        

        dp(i,j) = dp(i-1,j)+dp(i,j-1)

接下来就比较简单了

        求出马能走到的地方,直接封死标记:

        

const int dx[8]={-1,-2,-2,-1,1,2,2,1};
const int dy[8]={2,1,-1,-2,2,1,-1,-2};
int vis[50][50];

for(int i=0;i<8;i++){
	int xx=dx[i]+马的x坐标;
	int yy=dy[i]+马的y坐标;
	vis[xx][yy]=1;
}

最后再把上面的式子套上就可以了:

	for(int i=2;i<=bx;i++){
		for(int j=2;j<=by;j++){
			if(i==2&&j==2) continue;
			if(vis[i][j]==1) continue;
			dp[i][j] = dp[i-1][j]+dp[i][j-1];
		}
	}

!!!注意为了防止马越界,从2开始!

某人提供的六步法(思路概括)

1.找状态确定数组含义

        dp[i][j]表示走到i,j的位置可以采用的总方法数

2.找好转移

        式子已给出

3.确定你的推导顺序

        i : 从2->bx

        j : 从2->by

 4.确定好初始值

           dp[2][2]=1;

5.打印每一个转移结果

        不做解释

6.确定你想输出什么

        同上

注释代码

#include<bits/stdc++.h>
using namespace std;
int bx,by,hx,hy;
//判断能不能走
int vis[50][50];
long long dp[50][50];
//马的8个方位
const int dx[8]={-1,-2,-2,-1,1,2,2,1};
const int dy[8]={2,1,-1,-2,2,1,-1,-2};
int main(){
	//输入
	cin>>bx>>by>>hx>>hy;
	//防越界
	bx+=2;
	by+=2;
	hx+=2;
	hy+=2;
	//小兵是蒟蒻,不能吃马
	vis[hx][hy] = 1;
	//马的控制范围
	for(int i=0;i<8;i++){
		int xx=dx[i]+hx;
		int yy=dy[i]+hy;
		vis[xx][yy]=1;
	}
	//初始值
	dp[2][2]=1;
	//已做解释~
	for(int i=2;i<=bx;i++){
		for(int j=2;j<=by;j++){
			if(i==2&&j==2) continue;
			if(vis[i][j]==1) continue;
			dp[i][j] = dp[i-1][j]+dp[i][j-1];
		}
	}
	//输出
	cout<<dp[bx][by];
	return 0;
}

纯净代码:

#include<bits/stdc++.h>
using namespace std;
int bx,by,hx,hy;
int vis[50][50];
long long dp[50][50];
const int dx[8]={-1,-2,-2,-1,1,2,2,1};
const int dy[8]={2,1,-1,-2,2,1,-1,-2};
int main(){
	cin>>bx>>by>>hx>>hy;
	bx+=2;
	by+=2;
	hx+=2;
	hy+=2;
	vis[hx][hy] = 1;
	for(int i=0;i<8;i++){
		int xx=dx[i]+hx;
		int yy=dy[i]+hy;
		vis[xx][yy]=1;
	}
	dp[2][2]=1;
	for(int i=2;i<=bx;i++){
		for(int j=2;j<=by;j++){
			if(i==2&&j==2) continue;
			if(vis[i][j]==1) continue;
			dp[i][j] = dp[i-1][j]+dp[i][j-1];
		}
	}
	cout<<dp[bx][by];
	return 0;
}

 AC记录

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值