

只包含4个整数,它们彼此用空格隔开,分别为xp,yp,xs,ys。并且它们的都小于10000000。
含一个整数,表示从点p到点s至少需要经过的马步移动次数。
贪心+暴力/打表找规律
首先说贪心:
首先两个坐标相减取绝对值,使得问题变成从(x,y)到(0,0)的最短距离,然后先贪心,让(x,y)接近(0,0),剩下的路直接暴力bfs即可。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <queue>
using namespace std;
int x,y,fx[10][3],dis[105][105];
struct Point
{
int x,y;
};
void bfs()
{
memset(dis,-1,sizeof(dis));
dis[x][y]=0;
fx[1][1]=fx[2][1]=1,fx[3][1]=fx[4][1]=-1,fx[5][1]=fx[6][1]=2,fx[7][1]=fx[8][1]=-2;
fx[1][2]=fx[3][2]=2,fx[2][2]=fx[4][2]=-2,fx[5][2]=fx[7][2]=1,fx[6][2]=fx[8][2]=-1;
queue<Point> q;
Point p;
p.x=x,p.y=y;
q.push(p);
while (!q.empty())
{
Point x;
x=q.front();
q.pop();
for (int i=1;i<=8;i++)
{
int nowx=x.x+fx[i][1],nowy=x.y+fx[i][2];
if (nowx<0||nowy<0||nowx>100||nowy>100) continue;
if (dis[nowx][nowy]!=-1) continue;
dis[nowx][nowy]=dis[x.x][x.y]+1;
Point X;
X.x=nowx,X.y=nowy;
q.push(X);
if (nowx==50&&nowy==50) return;
}
}
}
int main()
{
int xp,yp,xs,ys;
scanf("%d%d%d%d",&xp,&yp,&xs,&ys);
x=abs(xs-xp),y=abs(ys-yp);
int ans=0;
while (x+y>=50)
{
if (x<y) swap(x,y);
if (x-4>=y*2) x-=4;
else x-=4,y-=2;
ans+=2;
}
x+=50,y+=50;
bfs();
printf("%d\n",ans+dis[50][50]);
return 0;
}
接下来说打表找规律:
(为了这个0ms做法花了好长时间。。)
0在图的正中央,他的坐标为(0,0)
可以发现到有颜色的最外圈颜色是间隔分布的。
现在只考虑右上角那一块,并且只看行序号>=列序号的部分,其他的全部忽略。
行数在>=3之后几乎可以说颜色是间隔分布了(注意是几乎!),很容易发现分布规律,2占1-2行,4占3-6行,6占7-10行。。。3占1-4行,5占5-8行,7占9-12行。。偶数和奇数分别有种前仆后继的感觉。
我还没有注意到“几乎”,直接按照间隔分布来做,拿了90分。。
然后再仔细看图发现了每行中的特殊点,用圆圈标出了。
发现他们都在对角线附近,那么可以通过走日字转移到对角线上(行数比列数每次多减去1),然后又可以发现对角线上的数字是有规律的从(4,4)开始为444666888。。。
于是对于能走到对角线上的特殊处理,不能走到对角线的按照前面的分布规律来做。
感悟:
大范围贪心+小范围暴力的做法值得借鉴。
原文:http://blog.csdn.net/regina8023/article/details/43963793