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

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;
}

你可能感兴趣的:([Hnoi2006]马步距离 (贪心+A*))