题目链接:P1002 [NOIP2002 普及组] 过河卒 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
会下象棋的大家都知道,过河卒是能左右移动的,而这道题说的是只能向右移动,这是一个区别,也简化了题目,像这道题用到的方法还是递推,和昨天那道题一样,即a[i][j] = a[i - 1][j] + a[i][j - 1]对吧,一个点的方法数就等于他左边那个点的方法数加上上边那个点的方法数,然后同理,就可以一直递推下去,假设没有马的存在,当目标坐标为(3,3)时,就可以得到如下图
因为两条边上的方法数很简单恒为1,只有1条路能到达
然后如果在复杂了也是同理,,,但现在的问题是多了一只🐎,那怎么办呢,有马的地方就是到不了的地方,将马和马控制的地方定为0?没错这样就可以了,但这里有个魔鬼细节,否则你最后提交有两个地方过不了,那就是当马控制的地方出现在特殊的两条边上,那么他后面的点就不是1了,而是0,这个不难理解吧,因为唯一的一条路被挡了,后面都到不了了
贴代码
#include<iostream>
using namespace std;
int main() {
long long a[22][22] = { 0 };
int bx, by, hx, hy;
cin >> bx >> by >> hx >> hy;
// for(int i=0;i<)
bx += 1, by += 1, hx += 1, hy += 1;
for (int i = 1; i <= 21; i++) {
if ((hx != 1 || hy != i) && (hx + 2 != 1 || hy - 1 != i) && (hx + 2 != 1 || hy + 1 != i) &&
(hx + 1 != 1 || hy + 2 != i) && (hx + 1 != 1 || hy - 2 != i) && (hx - 1 != 1 || hy - 2 != i) && (hx - 1 != 1 || hy + 2 != i)
&& (hx - 2 != 1 || hy - 1 != i) && (hx - 2 != 1 || hy + 1 != i))
a[1][i] = 1;
else
break;
}
for (int i = 1; i <= 21; i++) {
if ((hx != i || hy != 1) && (hx + 2 != i || hy - 1 != 1) && (hx + 2 != i || hy + 1 != 1) &&
(hx + 1 != i || hy + 2 != 1) && (hx + 1 != i || hy - 2 != 1) && (hx - 1 != i || hy - 2 != 1) && (hx - 1 != i || hy + 2 != 1)
&& (hx - 2 != i || hy - 1 != 1) && (hx - 2 != i || hy + 1 != 1))
a[i][1] = 1;
else
break;
}
for (int i = 2; i <= bx; i++) {
for (int j = 2; j <= by; j++) {
if ((i != hx || j != hy) && (i != hx - 2 || j != hy - 1) && (i != hx - 2 || j != hy + 1) && (i != hx - 1 || j != hy - 2)
&& (i != hx - 1 || j != hy + 2) && (i != hx + 1 || j != hy + 2) && (i != hx + 1 || j != hy - 2) &&
(i != hx + 2 || j != hy - 1) && (i != hx + 2 || j != hy + 1))
a[i][j] = a[i - 1][j] + a[i][j - 1];
}
}
cout << a[bx][by]<<"\n";
for (int i = 0; i < 22; i++) {
for (int j = 0; j < 22; j++)
cout << a[i][j] << " ";
cout << "\n";
}
return 0;
}
别看if里面一大堆,实际上就是避开马的控制位置,而break的作用就是上面的那个魔鬼细节的体现.