只包含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