竞赛算法之求解动态规划问题练习题(c++)-1

过河卒问题(动态规划问题)

(个人结题思路记录)

(cr洛谷 过河卒
棋盘上 A 点有一个过河卒,需要走到目标 BB 点。卒行走的规则:可以向下、或者向右。同时在棋盘上 C 点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。

棋盘用坐标表示,A 点 (0, 0)(0,0)、B 点 (n, m)(n,m),同样马的位置坐标是需要给出的。
在这里插入图片描述
现在要求你计算出卒从 AA 点能够到达 BB 点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。
输入格式
一行四个正整数,分别表示 BB 点坐标和马的坐标。

输出格式
一个整数,表示所有的路径条数。

输入输出样例
输入 #1
6 6 3 3
输出 #1
6

解题过程:一开始用的dfs,数据小的时候能解出来,但是大了会超时,基本思路就是最典型的dfs模型套用。下面是c++代码:

#include<iostream>
using namespace std;
int n,m,x,y;
long long  cnt;
int map[24][24];
int dx[2]={1,0};
int dy[2]={0,1};
//基本超过输入的nm基本超过15,运算起来就会超时了
//而且得出的cnt非常大,要注意定义数据类型,int肯定是不够 
int search(int xx,int yy)
{
	//最基本的dfs搜索模型套用 
	for(int i=0;i<2;i++)
	{
		int bx=xx+dx[i];
		int by=yy+dy[i];
		if(map[bx][by]==0 && bx>=0 && bx<=n && by>=0 && by<=m)
		{
			map[bx][by]=1;
			if(bx==n &&by==m) cnt++;
			else search(bx,by);
			map[bx][by]=0;//回溯		
		}
	}
}
int main(){
	cin>>n>>m>>x>>y;
	map[x][y]=-1;
	//标记马控制的点 ,这里写的有点麻烦了,可以定义数据用循环实现的 
	if(x+1>=0&&x+1<=n&&y-2>=0&&y-2<=m) map[x+1][y-2]=-1;
	if(x+2>=0&&x+2<=n&&y-1>=0&&y-1<=m) map[x+2][y-1]=-1;
	if(x+2>=0&&x+2<=n&&y+1>=0&&y+1<=m) map[x+2][y+1]=-1;
	if(x+1>=0&&x+1<=n&&y+2>=0&&y+2<=m) map[x+1][y+2]=-1;
	if(x-1>=0&&x-1<=n&&y+2>=0&&y+2<=m) map[x-1][y+2]=-1;
	if(x-2>=0&&x-2<=n&&y+1>=0&&y+1<=m) map[x-2][y+1]=-1;
	if(x-2>=0&&x-2<=n&&y-1>=0&&y-1<=m) map[x-2][y-1]=-1;
	if(x-1>=0&&x-1<=n&&y-2>=0&&y-2<=m) map[x-1][y-2]=-1;
	
	if(map[n][m]==-1) cnt=0;//如果b点在马控制的位置那么是无法到的 
	else search(0,0);
	cout<<cnt; 
	return 0;
} 

应用动态规划思想求解思路

基本上也是很基础的思路,首先考虑边界,然后就是状态转移方程。不难想出,想要到达i,j位置,有两条路径:从i-1,j,以及,i,j-1,所以可以得出如果我们用f[][]来记录到达i,j的路径数,那么f[i][j]=f[i-1][j]+f[i][j-1],但是应用之后会发现有问题,正确的状态转移方程应该是f[i][j]=max(f[i][j],f[i-1][j]+f[i][j-1]),为啥,测几组数据就想明白了。

#include<iostream>
#include<algorithm>
using namespace std;
int fx[9]={0,-2,-1,1,2,2,1,-1,-2};
int fy[9]={0,1,2,2,1,-1,-2,-2,-1};
//这是所有马能走到的位置 
int s[30][30];//记录当前位置是不是马控制的点 
long long  f[30][30];//记录从0,0到大i,j的线路数,数值可能会很大,注意数据类型 

int main(){
	
	int n,m,x,y;
	cin>>n>>m>>x>>y;
	n+=2;m+=2;x+=2;y+=2;
	//防止数组越界出错 
	f[2][2]=1;//初始化边界 
	s[x][y]=1;//马的位置 
	for(int i=1;i<=8;i++)
	   s[x+fx[i]][y+fy[i]]=1;//标注吗控制的点 
	for(int i=2;i<=n;i++)
	for(int j=2;j<=m;j++)
	{
		if(s[i][j]) continue;
		f[i][j]=max(f[i][j],f[i-1][j]+f[i][j-1]);
		//状态转移方程, 注意
		/*注意,这里如果直接f[i][j]=f[i-1][j]+f[i][j-1]是计算不出的*/ 
	}
	cout<<f[n][m];
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值