描述
棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。同时在棋盘上的某一点有一个对方的马(如C点),该马所在的点和所有跳跃一步可达的点称为对方马的控制点,如图3-1中的C点和P1,……,P8,卒不能通过对方马的控制点。棋盘用坐标表示,A点(0,0)、B点(n, m) (n,m为不超过20的整数),同样马的位置坐标是需要给出的,C≠A且C≠B。现在要求你计算出卒从A点能够到达B点的路径的条数。
格式
输入格式
给出n、m和C点的坐标。
输出格式
从A点能够到达B点的路径的条数。
样例
输入样例
8 6 0 4
输出样例
1617
限制
时间限制: 1000 ms
内存限制: 65536 KB
这题完全可以套用深搜/广搜的模板来写,但是深搜/广搜对于所需时间复杂度大的样例会显得无能为力,所以这种方法只过了60%,不能AC。
//深搜dfs
#include
using namespace std;
int dx[2] = {0, 1};
int dy[2] = {1, 0};
int ans=0, n, m, x, y;
int a[25][25];
void dfs(int, int);
int main ()
{
scanf ("%d %d %d %d", &n, &m, &x, &y);
memset(a, 0, sizeof(a));
a[x][y] = 1;
a[x-1][y-2] = 1;
a[x-1][y+2] = 1;
a[x-2][y-1] = 1;
a[x-2][y+1] = 1;
a[x+1][y-2] = 1;
a[x+1][y+2] = 1;
a[x+2][y-1] = 1;
a[x+2][y+1] = 1;
dfs(0, 0);
printf ("%d", ans);
return 0;
}
void dfs(int x1, int y1){
if (x1 == n && y1 == m) {
ans++;
return;
}
for (int i=0; i<2; i++) {
int tmpx = x1 + dx[i];
int tmpy = y1 + dy[i];
if (a[tmpx][tmpy] != 1 && tmpx<=n && tmpy<=m ) {
dfs(tmpx, tmpy);
}
}
}
关于dp动规,这里转贴一位刘知昊博主AC的代码(很详细)。过河卒可以说是动规入门级题目,所以题目难度不大,把状态转移方程想出,然后按套路走就行。
//dp动规递推
#include
#include //用scanf(),printf()输入输出加快速度
#include //cstring内有memset()函数
using namespace std;
int a[9]={0,-1,-1,-2,-2,1,1,2,2}; //数组a[]存储马控制的横坐标范围
int b[9]={0,2,-2,1,-1,2,-2,1,-1};
//数组b[]存储马控制的纵坐标范围,注意相同下标的a,b之间有一定的对应关系,
//即除了(0,0)外|a|与|b|一个为1,另一个为2
int n,m,x,y,i,j;
int map[21][21]; //map[i][j]表示地图上(i,j)这个点是否是马的控制点
long long tripnum[21][21]; //tripnum[i][j]表示从(0,0)到(i,j)卒合法的行走路线总数
int main()
{
memset(tripnum,0,sizeof(tripnum));
scanf("%d%d%d%d",&n,&m,&x,&y);
for(i=0;i<=20;i++)
for(j=0;j<=20;j++)
map[i][j]=1; //map[i][j]为1时表示(i,j)非控制点
for(i=0;i<=8;i++)
if(x+a[i]<=20 && x+a[i]>=0 && y+b[i]<=20 && y+b[i]>=0) //如果控制点在地图范围内,即这个点存在
map[x+a[i]][y+b[i]]=0; //将其设为0,表示这里被马控制
for(j=0;j<=20;j++) //从左到右遍历最上面一行的所有点
if(map[0][j]==1) //如果这个点不是控制点
tripnum[0][j]=1; //那么从(0,0)到达这个点的路线自然只有一条
else //否则这点不可到达,路线数为初值0条
break; //并且其右的点也不可达,不必继续遍历
for(i=0;i<=20;i++) //从上到下遍历最左边一列的所有点
if(map[i][0]==1) //如果这个点不是控制点
tripnum[i][0]=1; //那么从(0,0)到达这个点的路线自然只有一条
else //否则这点不可到达,路线数为初值0条
break; //并且其下的点也不可达,不必继续遍历
for(i=1;i<=n;i++) //从(1,1)这个点开始,逐行的去看(也可以逐列)
for(j=1;j<=m;j++)
if(map[i][j]==1) { //如果这个点不是控制点
tripnum[i][j]=tripnum[i-1][j]*map[i-1][j]
+tripnum[i][j-1]*map[i][j-1];
//那么到达它的路线数等于其左的点路线与其上的点之和,
//由于其左与其上的点有可能是控制点,所以要乘以控制系数map[i][j]
//(这也是为什么用0代表控制,而用1代表非控制,而不是调换过来的原因)
}
printf("%lld",tripnum[n][m]);
return 0;
}