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
样例输出
一、思路
感觉这是个回溯或者暴力求解的题目,怎么就可以用动态规划,发现还真可以
根据题目和加法原理
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;
}