大致题意: 给定一匹马的\(n\)种跳动方式,询问它是否能跳到无限棋盘上的所有点。
前言
现在越来越菜了,这种\(SB\)题还要想半天。
发现最近做题总是会莫名其妙走到死胡同里,就好比这题,一开始想歪了就一发不可收拾,最后还是因为知道这是\(SB\)题才会想出该怎么做。
一些能写的剪枝最后都懒得写了(而且一看好像大家都在写\(BFS\)就我写了个\(DFS\)?果然DFS才是我的真爱),成功成为了黑暗爆炸OJ上跑的最慢的代码。
暴搜
考虑一匹马能跳到所有点,就说明它通过若干步向四个方向分别都能跳动一个点。
马单次跳动步长是\(-100\sim 100\),假设我们令马从\((100,100)\)开始跳,那么就让它在\(200\times 200\)的棋盘上一直跳跳跳,跳到跳过的点直接\(return\)。
然后最后判断是否跳到过\((99,100),(101,100),(100,99),(100,101)\)这四个点即可。
显然这一过程可以加一堆剪枝,例如找到答案立刻退出、优先搜可能得到更优策略的情况等等,反正它又不卡我,也就都懒得去写了。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 200
using namespace std;
int n,dx[N+5],dy[N+5],vis[N+5][N+5];
I void dfs(CI x,CI y,CI ti)//暴搜
{
if(x<0||x>200||y<0||y>200||vis[x][y]==ti) return;vis[x][y]=ti;//越界或已搜过就不再搜
for(RI i=1;i<=n;++i) dfs(x+dx[i],y+dy[i],ti);//枚举方向跳动
}
int main()
{
RI Tt,T,i;for(scanf("%d",&Tt),T=1;T<=Tt;++T)
{
for(scanf("%d",&n),i=1;i<=n;++i) scanf("%d%d",dx+i,dy+i);dfs(100,100,T),
puts(vis[99][100]==T&&vis[101][100]==T&&vis[100][99]==T&&vis[100][101]==T?"TAK":"NIE");//判断是否能向四个方向跳动一步
}return 0;
}