过河卒-动态规划+高精度

http://www.rqnoj.cn/Problem_69.html


题目:过河卒

问题编号:69

题目描述

  如图,A 点有一个过河卒,需要走到目标 B 点。卒行走规则:可以向下、或者向右。同时在棋盘上的任一点有一个对方的马(如上图的C点),该马所在的点和所有跳跃一步可达的点称为对方马的控制点。例如上图 C 点上的马可以控制 9 个点(图中的P1,P2 … P8 和 C)。卒不能通过对方马的控制点。 

  棋盘用坐标表示,A 点(0,0)、B 点(n,m)(n,m 为不超过 25 的整数,并由键盘输入),同样马的位置坐标是需要给出的(约定: C<>A,同时C<>B)。现在要求你计算出卒从 A 点能够到达 B 点的路径的条数。

输入格式

键盘输入
   B点的坐标(n,m)以及对方马的坐标(X,Y){不用盘错}

输出格式

 屏幕输出
    一个整数(路径的条数)。

样例输入

6 6 3 2

样例输出

17


一、思路

感觉这是个回溯或者暴力求解的题目,怎么就可以用动态规划,发现还真可以

根据题目和加法原理

f(n,m) = f(n-1,m) + f(n, m-1) 上方和左方的可达路径之和,最优子结构

f(n-1, m) = f(n-2, m) + f(n-1, m-1)

f(n, m-1) = f(n-1, m-1) + f(n, m-2)

重复了f(n-1, m-1) 后面会重复更多,子问题重叠

利用2维数组来描述f[i][j]

怎么来递推求解,初始条件是什么

原本我想从0.0开始向右,向下,发现要考虑的边界条件和马的控制点,太多了


还是从递推式入手容易,初始条件为

f[0][i],第一行,只像右移动

f[i][0],第一列,只像下移动

然后从1,1开始求解,将马足控制点设为-2,此点不走,且,如果上或者左侧点为它,则把它记为0路径相加

if (f[i][j]==-2) continue;

f[i][j] = f[i-1][j]<0 ? 0 : f[i-1][j]

f[i][j] += f[i][j-1]<0 ? 0 : f[i][j-1];


因为题目最大数据为50里取25的排序数,用高精度

所以又加了第三维,来描述位数


二、算法

f[26][26][2],来描述当走到第i,j位置时的路径数f[i][j][2](低位为[0],高位为[1])

结构体 horse[9] 来描述定义,9个马的控制方位,用于初始化为:-2

1、读入b:n,m ;x,y

2、初始化

f[0][i]和f[i][0]和f[0][0]=1

3、动态规划求解,二重循环

第一重:行

第二重:列

       高精度,加法

4、输出结果f[n][m][0-1]

   输出最高位

   补0输出低位


三、错误总结

先是没有用高精度,只有2个得分点

后面用了,是6个得分点

1630 -->1645 输出的结果,比正确的少了十几个路径数

那么高精度和动态规划算法总体应该是没问题的,

最后发现是在初始化行列的时候,将n,m位置写错导致


终于AC

代码如下:

#include <iostream.h>
#include <fstream.h>

struct Point
{
	int x;
	int y;
};

#define BITS 10000000

//输出测试结果
void PrintF(int f[26][26][2], int n, int m)
{
	/*
	cout<<endl;
	for (int i=0; i<=n; i++)
	{
		for (int j=0; j<=m; j++)
		{
			cout<<f[i][j][0]<<"    ";
		}
		cout<<endl;
	}
	cout<<endl;
	*/
}

int main()
{
	int n, m, x, y;
	int f[26][26][2] = {0};
	Point horse[9] = {{0,0}, {-1,-2}, {-1,2}, {1,-2}, {1, 2},
	{2, -1}, {2,1}, {-2, 1}, {-2, -1}};
	int i, j;
   // ifstream inFile("e:\\test.txt");

	//读入B,和horse坐标
	cin>>n>>m>>x>>y;
	//inFile>>n>>m>>x>>y;
	//初始化,马的控制点,设为,-2
	for (i=0; i<9; i++)
	{
		if (x+horse[i].x>=0 && y+horse[i].y>=0)
		{
			f[x+horse[i].x][y+horse[i].y][0] = -2;
		}
	}
	PrintF(f, n, m);
	//初始化第一行
	f[0][0][0] = 1;
    
	for (i=1; i<=m; i++)
	{
		if (f[0][i][0] == -2)
		{
			continue;
		}
		f[0][i][0] = f[0][i-1][0]<0 ? 0 : f[0][i-1][0];
	}
	//初始化第一列
	for (i=1; i<=n; i++)
	{
		if (f[i][0][0] == -2)
		{
			continue;
		}
		f[i][0][0] = f[i-1][0][0]<0 ? 0 : f[i-1][0][0];
	}

    	PrintF(f, n, m);
	//动态规划求解
	//f(i,j)=f(i-1,j)+f(i, j-1);
	for (i=1; i<=n; i++)
	{
		for (j=1; j<=m; j++)
		{
			if (f[i][j][0] == -2)
			{
				continue;
			}
			f[i][j][0] += f[i-1][j][0]<0 ? 0 : f[i-1][j][0];
			f[i][j][1] += f[i-1][j][1];
			f[i][j][0] += f[i][j-1][0]<0 ? 0 : f[i][j-1][0];
			if (f[i][j][0]>BITS)
			{
				f[i][j][1] += f[i][j][0]/BITS;
				f[i][j][0] = f[i][j][0]%BITS;
			}
                        f[i][j][1] += f[i][j-1][1];
		} 
	}

		PrintF(f, n, m);
	//输出结果
	//找到最高位
    i=1;
	while (!f[n][m][i])
	{
		i--;
	}
	//输出最高位
	cout<<f[n][m][i];
	//补位输出低位
	for (j=i-1; j>=0; j--)
	{
	    //判断位数  
        int bit = 10;
		int cnt;
        for (cnt=1; cnt<=7; cnt++)  
        {  
            if (f[n][m][j]/bit==0)  
            {  
                break;  
            }  
            bit *= 10;  
        }  
        //输出0  
        for (int k=1; k<=7-cnt; k++)  
        {  
            cout<<0;  
        }  
        cout<<f[n][m][j];  
	}



	

	//inFile.close();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值