http://begin.lydsy.com/JudgeOnline/problem.php?id=1285
在国际象棋和中国象棋中,马的移动规则相同,都是走“日”字,我们将这种移动方式称为马步移动。如右图所示,从标号为0的点出发,可以经过一步马步移动达到标号为1的点,经过两步马步移动达到标号为2的点。
任给平面上的两点p和s,它们的坐标分别为(xp,yp)和(xs,ys),其中,xp,yp,xs,ys均为整数。从(xp,yp)出发经过一步马步移动 可以达到(xp+1,yp+2)、(xp+2,yp+1)、(xp+1,yp-2)、(xp+2,yp-1)、(xp-1,yp+2)、(xp- 2,yp+1)、(xp-1,yp-2)、(xp-2,yp-1)。假设棋盘充分大,并且坐标可以为负数。现在请你求出从点p到点s 至少需要经过多少次马步移动?
Input
只包含4个整数,它们彼此用空格隔开,分别为xp,yp,xs,ys。并且它们的都小于10000000。
Output
含一个整数,表示从点p到点s至少需要经过的马步移动次数。
Sample Input
1 2 7 9
Sample Output
5
HINT
Source
直接暴搜,MLE;换A*,MLE;后来在网上看了题解,先用贪心然后再搜索(普通BFS也可以过)。
具体贪心策略:在大范围内先尽量接近目标点,然后在小范围使用搜索即可。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int INF=0x3f3f3f3f; const int maxn=210; int T,n,m; int sx,sy,ex,ey; int ans; struct node{ int x,y; int g,h,f; int step; bool operator < (const node &a) const { return f>a.f; } }; int dx[]={-2,-2,-1,-1,1,1,2,2}; int dy[]={-1,1,-2,2,-2,2,-1,1}; int Heuristic(int x,int y){//manhattan估价函数 return (abs(x-ex)+abs(y-ey))*10; } void Astar(){ priority_queue<node>q; node s,e; s.x=sx,s.y=sy,s.step=0; s.g=0,s.h=Heuristic(sx,sy),s.f=s.g+s.h; q.push(s); while(!q.empty()){ s=q.top();q.pop(); if(s.x==ex&&s.y==ey){ cout<<ans+s.step<<endl; return ; } for(int i=0;i<8;i++){ e.x=s.x+dx[i],e.y=s.y+dy[i],e.step=s.step+1; e.g=s.g+23,e.h=Heuristic(e.x,e.y),e.f=e.g+e.h; q.push(e); } } return ; } int main() { #ifndef ONLINE_JUDGE freopen("test.in","r",stdin); freopen("test.out","w",stdout); #endif while(~scanf("%d%d%d%d",&sx,&sy,&ex,&ey)){ ans=0; ex=abs(sx-ex); ey=abs(ey-sy); while(ex>=10||ey>=10){ if(ex>ey) ex-=2,ey-=1; else ex-=1,ey-=2; ans++; ex=abs(ex),ey=abs(ey); } sx=0,sy=0; Astar(); } return 0; }