【题目来源】
http://oj.ecustacm.cn/problem.php?id=1810
http://oj.ecustacm.cn/viewnews.php?id=1023
https://www.acwing.com/problem/content/3887/
【题目描述】
现在在一个无限大的平面上,给你一个超级骑士。
超级骑士有N种走法,请问这个超级骑士能否到达平面上的所有点。
每种走法输入两个数字 xx 和 yy,表示超级骑士可以从任意一点 (x,y) 走到 (x+xx,y+yy)。
【输入格式】
输入第一行为正整数 T,表示存在 T 组测试数据。(1≤T≤100)
对于每组测试数据,第一行输入正整数 N,表示有 N 种走法。(1≤N≤100)
接下来N行,每行两个正整数 xx 和 yy。(-100≤xx,yy≤100)
【输出格式】
对于每组测试数据,如果可以到达平面上所有点,输出Yes,否则输出No。
【输入样例】
2
3
1 0
0 1
-2 -1
5
3 4
-3 -6
2 -2
5 6
-1 4
【输出样例】
Yes
No
【算法分析】
因为题意会走回头路,所以不能用动态规划算法,需要用 BFS 或 DFS 算法。由于题意规定每步走法由输入的两个数字 xx 和 yy 决定,表示超级骑士可以从任意一点 (x,y) 走到 (x+xx,y+yy),且 -100≤xx, yy≤100。不失一般性,可将起点设为 (100,100)。若设 (xx,yy) 为 (-100,-100)、(-100,100)、(100,-100)、(100,100),那么走一步最远可到 (100-100,100-100)、(100-100,100+100)、(100+100,100-100)、(100+100,100+100),即 (0, 0)、(0, 200)、(200, 0)、(200, 200)。◆
虽然题目问能不能到达所有的点,但其实不用真的检查是否能到所有的点。只需检查从某个任意点 (sx, sy) 出发,存在 (sx, sy) 的上、下、左、右的点都可到达,可立即返回“Yes”,不用再遍历其他的点,这就是剪枝的应用。这是因为,若给定的走法能够保证存在某个任意点 (sx, sy) 的上、下、左、右的点都可到达,那么平面上的任意点都可达。或从直观上分析,能否走到平面上的所有点,取决于骑士走法的粒度(或称步幅),粒度越小越有可能达到所有点。如输入样例中的 (1,0)、(0,1)、(-2,-1),因为粒度较小,平面上的所有点都可达。而输入样例中的 (3,4)、(-3,-6)、(2,-2)、(5,6)、(-1,4),因为粒度较大,平面上有的点就走不到。◆
DFS算法模板:https://blog.csdn.net/hnjzsyjyj/article/details/125801217◆
void dfs(int step){
判断边界{
输出解
}
尝试每一种可能{
满足check条件{
标记
继续下一步:dfs(step+1)
恢复初始状态(回溯的时候要用到)
}
}
}
BFS算法模板:https://blog.csdn.net/hnjzsyjyj/article/details/118736059◆
助记:建-入-量:头-出-入”。
其中,“建-入-量:头-出-入”各字的解析如下:
建:建队
入:入队
量:队中元素个数。作为while循环的条件。
头:队头
出:出队
入:入队
一个记忆场景,“小猫咪在建好的洞口,想入洞。先用胡子量过洞口大小后,然后用头出入洞”。
【算法代码】
#include<bits/stdc++.h>
using namespace std;
const int maxn=105;
int dx[maxn],dy[maxn];
bool f[2*maxn][2*maxn];
int sx=100,sy=100;
int n;
bool dfs(int x, int y) {
f[x][y]=true;
if(f[sx-1][sy] && f[sx+1][sy] && f[sx][sy-1] && f[sx][sy+1]) { //prune
return true;
}
for(int i=1; i<=n; i++) {
int nx=x+dx[i];
int ny=y+dy[i];
if(nx<0 || nx>200 || ny<0 || ny>200) continue; //check boundary
if(f[nx][ny]) continue; //having gone
if(dfs(nx,ny)) return true;
}
return false;
}
int main() {
int T;
cin>>T;
while(T--) {
cin>>n;
for(int i=1; i<=n; i++) {
cin>>dx[i]>>dy[i];
}
memset(f,0,sizeof(f));
if(dfs(sx,sy)) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}
/*
in:
2
3
1 0
0 1
-2 -1
5
3 4
-3 -6
2 -2
5 6
-1 4
out:
Yes
No
*/
【参考文献】
https://blog.csdn.net/weixin_43914593/article/details/131791202