您的位置:首页 > 其它

[Hnoi2006]马步距离 (贪心+A*)

2016-04-05 16:48 323 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: