题目
题意:给定若干查询,每次查询从(0,0)到点
(
x
,
y
)
(x,y)
(x,y)需要的最小步数,
0
<
=
x
,
y
<
=
50
0<=x,y<=50
0<=x,y<=50。点
(
x
1
,
y
1
)
(x_1,y_1)
(x1,y1)能走到
(
x
2
,
y
2
)
(x_2,y_2)
(x2,y2),当且仅当它们直接的距离是整数,即
(
(
x
1
−
x
2
)
2
+
(
y
1
−
y
2
)
2
)
\sqrt{((x_1-x_2)^2+(y_1-y_2)^2)}
((x1−x2)2+(y1−y2)2)是整数。
思路:找出50以内的所有沟谷数,注意考虑同一x轴、同一y轴的点,也是可达的。bfs广搜,注意搜上下左右四个方向。
ps:一开始只想着自己手动枚举50内的所有沟谷数。wa了后,一拍脑袋,我是不是傻,直接暴力预计算就行啊,50*50。最后发现,好吧,自己算漏了28 45 这对勾股数。果然,我的脑子没有电脑好用233。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 500010;
//int dx[] = {3, 5, 8, 7, 9, 12, 20, 4, 12, 15, 24, 40, 35, 21, 0, 1};
//int dy[] = {4, 12, 15, 24, 40, 35, 21, 3, 5, 8, 7, 9, 12, 20, 1, 0};
//int dnum = 16;
vector<int> vx, vy;
int dx[] = {1, -1, 1, -1};
int dy[] = {1, -1, -1, 1};
int dnum = 4;
int mp[55][55];// 与(0,0)的最小距离
int n = 50, m = 50;
bool check(int x, int y) {
return (0 <= x && x <= n) &&
(0 <= y && y <= m);
}
void bfs() {
memset(mp, -1, sizeof(mp));
mp[0][0] = 0;
int vsz = vx.size();
queue<pair<int, int> > q;
q.push({0, 0});
int deep = 0;
while (!q.empty()) {
int sz = q.size();
++deep;// 层数记录
while (sz--) {
pair<int, int> cur = q.front();
q.pop();
int x = cur.first, y = cur.second;
for (int i = 0; i < vsz; ++i) {
for (int j = 0; j < dnum; ++j) {
int qx = x + vx[i] * dx[j], qy = y + vy[i] * dy[j];
if (check(qx, qy) && mp[qx][qy] == -1) {
mp[qx][qy] = deep;
q.push({qx, qy});
}
}
}
}
}
}
void solve() {
int x, y;
scanf("%d%d", &x, &y);
printf("%d\n", mp[x][y]);
}
void pre() {
vx.clear();
vy.clear();
// 存储所有勾股数
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
int z = i * i + j * j;
int sq = sqrt(z);
if (sq * sq == z) {
// printf("%d %d\n", i, j);
vx.push_back(i);
vy.push_back(j);
}
}
}
// 存储同x轴 同y轴的点
for (int i = 1; i <= n; ++i) {
vx.push_back(i);
vy.push_back(0);
vx.push_back(0);
vy.push_back(i);
}
}
int main() {
pre();
bfs();
int t;
scanf("%d", &t);
while (t--) {
solve();
}
}
/*
0 1
3 4
5 12
8 15
7 24
9 40
12 35
20 21
还有
28 45
*/