Root M Leaper 根号M的跳跃
我的翻译!
思路
考虑广搜,棋子第一次到达某个方格用的步数就是这个方格的答案。但不要盲目地搜,需要纸上计算一下位于
-
求出
x 的范围。设L=\sqrt M ,因为距离为L ,x 是整数,横坐标应满足\hspace9ex\lceil X-L\rceil \le x \le \lfloor X+L\rfloor\hspace10ex (1) 即
\hspace10ex\ X-\lfloor L\rfloor \le x \le i+\lceil L\rceil\hspace10ex (2) -
由题意可知:
\hspace4ex \sqrt {(X-x)^2+(Y-y)^2}=\sqrt M \hspace10ex(3) \ \ \iff (X-x)^2+(Y-y)^2=M \hspace11ex(4)
现在
把
解得:
显然,若
实际上,这个题也可以用圆的方程数形结合来考虑:目标点共圆,半径为
由于
代码
#include<bits/stdc++.h>
using namespace std;
struct node{
int x,y,step;
node(int x,int y,int step):x(x),y(y),step(step){}//构造函数
};queue<node>q;
bool check(int d){//判断Δ是否是完全平方数
int sd=sqrt(d);
if(sd*sd==d)return true;
return false;
}int n,m,mp[405][405];
void Upd(int x,int y,int data){
if(y<=n&&y>=1&&mp[x][y]==-1){
mp[x][y]=data;
q.push(node(x,y,data));
}
}
signed main(){
cin>>n>>m;
memset(mp,-1,sizeof(mp));
/*小技巧:初始化为-1,既可以判断是否访问,
又可以在无法访问时报错*/
mp[1][1]=0;
q.push(node(1,1,0));
while(!q.empty()){
node h=q.front();q.pop();
int lim=sqrt(m),i=h.x,j=h.y;//int 类型已经帮我们向下取整了
for(int k=max(1,h.x-lim);k<=min(n,h.x+lim);k++){//max 和 min 函数帮我们逃离过大的 m 导致的问题
int delta=m-(i-k)*(i-k);
if(check(delta)){
Upd(k,j+sqrt(delta),h.step+1);
Upd(k,j-sqrt(delta),h.step+1);
}
}//这里的 k 相当于枚举可能的 x
}for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
printf("%d ",mp[i][j]);
}puts("");
}
return 0;
}