zoukankan      html  css  js  c++  java
  • [JZOJ1320] 【Usaco2009 gold 】拯救奶牛

    题目

    在这里插入图片描述

    题目大意

    一个三角形的网格图,三角形与其有共同边的三角形相连。
    起点到所有终点的最短距离。


    思考历程

    数据看起来还挺大的,所以不是什么图论算法。
    这显然是一个结论题。
    什么结论?
    然后我就开始推:
    一个点(x,y)(x,y),它可以到达(x,y1)(x,y+1)(x,y-1)(x,y+1)
    如果yy是奇数,那么可以到达(x+1,y+1)(x+1,y+1),否则可以到达(x1,y1)(x-1,y-1)
    将其在平面直角坐标系中表示出来,得到一个很好看的图(懒得画了)。
    感性地想出了一个式子,感觉上好像没什么问题,打了交上去。
    结果60分……


    正解

    这个方法有很多。

    假设起点是上面那个(反正边是双向的),现在它要往下走:
    如果它是正三角形,意味着它可以直接往下走。
    如果它是倒三角形,就将其向左或向右一个,那就是正三角形的情况了。
    可以推推式子,求出它走最短距离到达终点那一行的左右边界。
    所谓走最短距离,就是先往下走,然后向左或向右,继续向下……
    如果终点在边界内,答案就是最短距离。否则走到终点那一行的左边界或右边界,然后左右移动到终点。

    还有一种特别好的方法。
    我们如果只考虑上下走,那么对于那两个点来说,不管怎样,一定会走它们层数之差的距离。
    这是我们以(1,1)(1,1)为端点的情况,那不妨考虑一下,将图旋转六十度,以(n,1)(n,1)(n,2n1)(n,2n-1)为顶点。
    所以我们只需要算出它们分别以三个顶点的层数之差,加起来,就是答案。
    比较好理解,所以我的程序打的就是这种方法。


    代码

    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
    %d",ansx,ansy,ans+1);
    	return 0;
    }
    

    总结

    题目不要想得太复杂……
    能用一个三角形来想的题目就不要傻傻地用平面直角坐标系来想……

  • 相关阅读:
    mysql优化之索引优化
    mysqld --debug-sync
    mysql.cnf 配制文件详解
    my.cnf 中字符集设置
    tcp_tw_reuse 与 net.ipv4.tcp_tw_recycle
    mysql init_connect 参数的其他用处
    监控mysql索引使用效率的脚本
    mysql 源代码学习 博客 [lock..]
    mysqld with valgrind
    思维导图软件
  • 原文地址:https://www.cnblogs.com/jz-597/p/11145234.html
Copyright © 2011-2022 走看看