BZOJ系列1193《[HNOI2006]马步距离》题解

Description

Input

只包含4个整数,它们彼此用空格隔开,分别为xp,yp,xs,ys。并且它们的都小于10000000。

Output

含一个整数,表示从点p到点s至少需要经过的马步移动次数。

Sample Input

1 2 7 9

Sample Output

5

分析:好熟悉,去年NOIP前老师出的模拟赛用过,差不多。

当时的题是某个点到原点的,这道题是两个点之间的,差不多,没什么区别。。。

策略就是:搜索+贪心优化搜索范围。

两个点间的距离比较大,纯搜索不现实,所以需要找到一个规律。

这就需要贪心优化了,因为走得步子是有规律的,所以可以按这个规律将两个点的距离拉近。

本题将两个点拉到了100*100的方框内,足以搜索了。

下面说一下怎么贪心:

先将一个点置于原点,另一个点置于第一象限。

while(x+y>=50)
{
        if(x=2*y) x-=4;
        else x-=4,y-=2;
        ans+=2;
}
x+=50,y+=50;
x和y代表两点间的横纵距离。

然后广搜!!

我们知道马走的方式,就可以枚举出每个点该怎么走,直到走到终点(50,50),再加上贪心时走过的ans。

输出AC。


代码如下:

#include
#include
#include
#include
#include
using namespace std;
const int dx[8]={1,1,-1,-1,2,2,-2,-2};
const int dy[8]={2,-2,2,-2,1,-1,1,-1};
int XP,YP,XS,YS,x,y,ans=0;
int q[100010][3],head=0,tail=1;
int d[110][110];
void init()
{
    scanf("%d%d%d%d",&XP,&YP,&XS,&YS);
    x=abs(XP-XS),y=abs(YP-YS);
    while(x+y>=50)
    {
        if(x=2*y) x-=4;
        else x-=4,y-=2;
        ans+=2;
    }
    x+=50,y+=50;
}
void BFS()
{
    memset(d,-1,sizeof(d));
    q[0][1]=x,q[0][2]=y,d[x][y]=0;
    while(head!=tail)
    {
        int x=q[head][1],y=q[head++][2];
        for(int i=0;i<8;i++)
        {
            int nx=x+dx[i],ny=y+dy[i];
            if(nx<0||ny<0||nx>100||ny>100||d[nx][ny]!=-1) continue;
            d[nx][ny]=d[x][y]+1;
            q[tail][1]=nx,q[tail++][2]=ny;
            if(nx==50&&ny==50) return;
        }
    }
}
void work()
{
    BFS();
    ans+=d[50][50];
    printf("%d\n",ans);
}
int main()
{
    init();
    work();
    return 0;
}

你可能感兴趣的:(BZOJ)