1314:【例3.6】过河卒(Noip2002)

1314:【例3.6】过河卒(Noip2002)(递推法/动态规划法)

时间限制: 1000 ms 内存限制: 65536 KB

提交数: 18186 通过数: 7756

目录

【题目描述】

棋盘上A点有一个过河卒,需要走到目标B点。

卒行走的规则:可以向下、或者向右。同时在棋盘上的某一点有一个对方的马(如C点),该马所在的点和所有跳跃一步可达的点称为对方马的控制点,如图3-1中的C点和P1,……,P8,卒不能通过对方马的控制点。棋盘用坐标表示,A点(0,0)、B点(n, m) (n,m为不超过20的整数),同样马的位置坐标是需要给出的,C≠A且C≠B。现在要求你计算出卒从A点能够到达B点的路径的条数。

1314:【例3.6】过河卒(Noip2002)

【输入】

给出n、m和C点的坐标。

【输出】

从A点能够到达B点的路径的条数。

【输入样例】

8 6 0 4

【输出样例】

1617

【题解】

思路:dfs会超时,卒只能向下或者向右走。可递推出路径数的总和:

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

最终的结果应该由 long long 保存。

【超时的DFS代码参考】

// https://www.freesion.com/article/52861256835/
#include<bits/stdc++.h>
using namespace std;
int a[21][21],vis[21][21],n,m,xx,yy,cnt=0;
int dir[8][2]={{-2,-1},{-1,-2},{2,-1},{1,-2},{2,1},{1,2},{-1,2},{-2,1}};
int dr[2][2]={{0,1},{1,0}};
bool check(int x,int y)
{
	if(vis[x][y]==0&&x>=0&&x<=n&&y>=0&&y<=m)return true;
	return false;
}
void dfs(int x,int y)
{
	if(x==n&&y==m)
	{
		cnt++;
		return;
	}
	for(int i=0;i<2;i++)
	{
		int nx=dr[i][0]+x;
		int ny=dr[i][1]+y;
		if(check(nx,ny))
		{
			vis[nx][ny]=1;
			dfs(nx,ny);
			vis[nx][ny]=0;
		}
	}
}
int main()
{
	cin>>n>>m>>xx>>yy;
	memset(vis,0,sizeof(vis));
	for(int i=0;i<8;i++)
	{
		int nx=xx+dir[i][0];
		int ny=yy+dir[i][1];
		if(nx>=0&&nx<=n&&ny>=0&&ny<=m&&vis[nx][ny]==0)
			vis[nx][ny]=1;
	}
	vis[xx][yy]=1;
	vis[0][0]=1;

	dfs(0,0);
	cout<<cnt<<endl;
	return 0;
}

【正确答案】

// https://www.freesion.com/article/52861256835/
#include<bits/stdc++.h>
using namespace std;
int vis[21][21],n,m,xx,yy;
int dir[8][2]={{-2,-1},{-1,-2},{2,-1},{1,-2},{2,1},{1,2},{-1,2},{-2,1}};
bool check(int x,int y)
{
	if(vis[x][y]==0&&x>=0&&x<=n&&y>=0&&y<=m)return true;
	return false;
}
long long f[21][21];
int main()
{
	cin>>n>>m>>xx>>yy;
	memset(vis,0,sizeof(vis));
	for(int i=0;i<8;i++)
	{
		int nx=xx+dir[i][0];
		int ny=yy+dir[i][1];
		if(nx>=0&&nx<=n&&ny>=0&&ny<=m&&vis[nx][ny]==0)
			vis[nx][ny]=1;
	}
	vis[xx][yy]=1;
	vis[0][0]=1;
	for(int i=1;i<=n;i++)
		if(vis[i][0])break;
		else f[i][0]=1;
	for(int i=1;i<=m;i++)
		if(vis[0][i])break;
		else f[0][i]=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			if(check(i,j))
			{
				f[i][j]=f[i-1][j]+f[i][j-1];
			}
		}
	}
	cout<<f[n][m]<<endl;
	return 0;
}

【我的答案】

# include <bits/stdc++.h>
using namespace std;

const int MAXLEN = 25;

long long int board[MAXLEN][MAXLEN];

const int direction[8][2] = {
	{ 1,  2},
	{-1,  2},
	{ 1, -2},
	{-1, -2},
	
	{ 2,  1},
	{-2,  1},
	{ 2, -1},
	{-2, -1}
};

int sizex, sizey;
int horsex, horsey;

# define CHECK(X,Y) ((X)>=0&&(X)<sizex&&(Y)>=0&&(Y)<sizey)

int main ()
{
	
	
	cin >> sizex >> sizey >> horsex >> horsey;
	sizex++;
	sizey++;
	
	board[horsex][horsey] = -1;	
	for(int i = 0; i < 8; i++){
		if(CHECK(horsex+direction[i][0], horsex+direction[i][0])){
			board[horsex+direction[i][0]][horsey+direction[i][1]] = -1;
		}
	}
	
	for(int y = 0; y < sizey; y++){
		if(board[0][y] == -1){
			board[0][y] = 0;
			break;// 很重要 ,从此往后都是0 
		}
		else{
			board[0][y] = 1;
		}
	}
	
	for(int x = 0; x < sizex; x++){
		if(board[x][0] == -1){
			board[x][0] = 0;
			break;// 很重要 ,从此往后都是0 
		}
		else{
			board[x][0] = 1;
		}
	}
	
	
	for(int x = 1; x < sizex; x++){
		for(int y = 1; y < sizey; y++){
			if(board[x][y] == -1){
				board[x][y] = 0;
			}
			else{
				board[x][y] = board[x-1][y] + board[x][y-1];
			}
		}
	}
	printf("%lld\n", board[sizex-1][sizey-1]);
	return 0;
}
// 2021年10月6日16:15:51

(完)

上一篇:1320:【例6.2】均分纸牌(Noip2002)


下一篇:题解 P1032 [NOIP2002 提高组] 字串变换