[JZOJ1320] 【Usaco2009 gold 】拯救奶牛
题目
题目大意
一个三角形的网格图,三角形与其有共同边的三角形相连。
起点到所有终点的最短距离。
思考历程
数据看起来还挺大的,所以不是什么图论算法。
这显然是一个结论题。
什么结论?
然后我就开始推:
一个点,它可以到达。
如果是奇数,那么可以到达,否则可以到达
将其在平面直角坐标系中表示出来,得到一个很好看的图(懒得画了)。
感性地想出了一个式子,感觉上好像没什么问题,打了交上去。
结果60分……
正解
这个方法有很多。
假设起点是上面那个(反正边是双向的),现在它要往下走:
如果它是正三角形,意味着它可以直接往下走。
如果它是倒三角形,就将其向左或向右一个,那就是正三角形的情况了。
可以推推式子,求出它走最短距离到达终点那一行的左右边界。
所谓走最短距离,就是先往下走,然后向左或向右,继续向下……
如果终点在边界内,答案就是最短距离。否则走到终点那一行的左边界或右边界,然后左右移动到终点。
还有一种特别好的方法。
我们如果只考虑上下走,那么对于那两个点来说,不管怎样,一定会走它们层数之差的距离。
这是我们以为端点的情况,那不妨考虑一下,将图旋转六十度,以或为顶点。
所以我们只需要算出它们分别以三个顶点的层数之差,加起来,就是答案。
比较好理解,所以我的程序打的就是这种方法。
代码
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
int main(){
int n,m,sx,sy,sz;
scanf("%d%d%d%d",&n,&m,&sx,&sy);
sz=(sx*2-sy-1)/2+1,sy=(sy-1)/2+1;
int ansx,ansy,ans=2147483647;
for (int i=1;i<=m;++i){
int x,y,z,t;
scanf("%d%d",&x,&y);
t=abs(x-sx)+abs((y-1)/2+1-sy)+abs((x*2-y-1)/2+1-sz);
if (t<ans || t==ans && (x<ansx || x==ansx && y<ansy))
ansx=x,ansy=y,ans=t;
}
printf("%d %d\n%d",ansx,ansy,ans+1);
return 0;
}
总结
题目不要想得太复杂……
能用一个三角形来想的题目就不要傻傻地用平面直角坐标系来想……