信息学奥赛一本通 1314:【例3.6】过河卒(Noip2002)

题目链接:点击这里
信息学奥赛一本通 1314:【例3.6】过河卒(Noip2002)_第1张图片

搜索,即便调试通过,当n、m==15就会超时。

其实,本题稍加分析就能发现,要到达棋盘上的一个点, 只能从左边过来(我们称之为左点)或是从上面过来(我们称之为上点),所以根据加法原理,到达某一点的路径数目,就等于到达其相邻的上点和左点的路径数目之和,因此我们可以使用逐列(或逐行)递推的方法来求出从起点到终点的路径数目。障碍点(马的控制点)也完全适用,只要将到达该点的路径数目设置为0即可。

用 f[i][j] 表示到达点 (i,j) 的路径数目,g[i][j] 表示 点(i, j) 有无障碍,g[i][j]==0表示无障碍,g[i][j]==1 表示有障碍。

则递推关系式如下:
f[i][j] = f[i-1][j] + f[i][j-1] //i>0且j>0且g[i][j]=0

递推边界如下:
f[0][0] = 1
f[i][0] = f[i-1][0] //i>0且g[i][0]=0
f[0][j] = f[0][j-1] //j>0且g[0][j]=0
f[i][j] = 0 //g[i][j]=1

#include
#include
#include
#include
#include
#include
#include
#include

using namespace std;
typedef long long ll;
const int MOD = 10000007;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
const int maxn = 1010;
int g[40][40];	//表示点(i, j) 有无障碍,有障碍为1,无障碍为0
long long f[40][40];	//表示到达点 (i,j) 的路径数目

int X[8] = {1, 1, -1, -1, 2, 2, -2, -2};
int Y[8] = {2, -2, 2, -2, 1, -1, 1, -1};

int main()
{
	int n,m,cx,cy;
	scanf("%d%d%d%d",&n,&m,&cx,&cy);
	
	//以下考虑马的控制点有无越界,并设置障碍为 1 
    g[cx][cy]=1;
    if(cx-1>=0&&cy-2>=0) g[cx-1][cy-2]=1;
    if(cx+1<=n&&cy-2>=0) g[cx+1][cy-2]=1;
    if(cx-2>=0&&cy-1>=0) g[cx-2][cy-1]=1;
    if(cx+2<=n&&cy-1>=0) g[cx+2][cy-1]=1;
    if(cx-2>=0&&cy+1<=m) g[cx-2][cy+1]=1;
    if(cx+2<=n&&cy+1<=m) g[cx+2][cy+1]=1;
    if(cx-1>=0&&cy+2<=m) g[cx-1][cy+2]=1;
    if(cx+1<=n&&cy+2<=m) g[cx+1][cy+2]=1;
	 
	//以下为递推边界
	f[0][0] = 1;
    
	for(int i=1; i<=n; i++)
        if(!g[i][0])
			f[i][0] = f[i-1][0];
    
	for(int j=1; j<=m; j++)
        if(!g[0][j])
			f[0][j] = f[0][j-1];
    
	//以下为递推关系式    
    for(int i=1; i<=n; i++)
    { 
        for(int j=1; j<=m; j++)
        {
            if(g[i][j])
				f[i][j]=0;
            if(!g[i][j])
				f[i][j]=f[i][j-1]+f[i-1][j];
        }
    } 
	printf("%lld\n",f[n][m]); 
	return 0;
}

你可能感兴趣的:(递推)