package practice;

import java.util.Scanner;

public class TreasureHunt {

    public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
int[][] walls;
float x, y;
int doors = Integer.MAX_VALUE, temp1, temp2;
int n = cin.nextInt();
walls = new int[n][4];
for (int j = 0; j < n; j++) {
walls[j][0] = cin.nextInt();
walls[j][1] = cin.nextInt();
walls[j][2] = cin.nextInt();
walls[j][3] = cin.nextInt();
}
x = cin.nextFloat();
y = cin.nextFloat();
for (int j = 0; j < n; j++) {
temp1 = find(walls[j][0], walls[j][1], x, y, walls, j);
temp2 = find(walls[j][2], walls[j][3], x, y, walls, j);
doors = temp1 < temp2 ? (temp1 < doors ? temp1 : doors)
: (temp2 < doors ? temp2 : doors);
}
if (n == 0)
doors = 0;
doors++;
System.out.println("Number of doors = " + doors);
} private static int find(int x1, int y2, float x, float y, int[][] walls,
int j) {
int count = 0;
for (int i = 0, len = walls.length; i < len; i++) {
if (i == j)
continue;
if (isIntersect(x1, y2, x, y, walls[i]))
count++;
}
return count;
} /**
*
* 跨立实验
*/
private static boolean isIntersect(int startX, int startY, float endX,
float endY, int[] wall) {
if ((Math.max(startX, endX) >= Math.min(wall[0], wall[2]))
&& (Math.max(wall[0], wall[2]) >= Math.min(startX, endX))
&& (Math.max(startY, endY) >= Math.min(wall[1], wall[3]))
&& (Math.max(wall[1], wall[3]) >= Math.min(startY, endY))
&& (multiply(wall[0], wall[1], endX, endY, startX, startY)
* multiply(endX, endY, wall[2], wall[3], startX, startY) > 0)
&& (multiply(startX, startY, wall[2], wall[3], wall[0], wall[1])
* multiply(wall[2], wall[3], endX, endY, wall[0],
wall[1]) > 0))
return true;
else
return false;
} private static double multiply(float x1, float y1, float x2, float y2,
float x3, float y3) {
return ((x1 - x3) * (y2 - y3) - (x2 - x3) * (y1 - y3));
} }

点我展开代码

该问题是:

一伙寻宝人探测到了埃及金字塔底层的宝藏,但是宝藏被n堵墙围着,如果要爆破,只能在每堵墙的中点开门。现在问题来了,对于随机给定的n堵墙,算出最少需要的开门数。

输入数据如下所示,第一行的整数n表示墙数,后面的n行表示墙体两端坐标,以金字塔边缘左下角为(0,0)右上角为(100,100),每行的四个数据分别为(x1,y1,x2,y2)

最后一行的数据表示宝藏点P的位置。

7
20 0 37 100
40 0 76 100
85 0 0 75
100 90 0 90
0 71 100 61
0 14 100 38
100 47 47 100
54.5 55.4

算法的思路很简单(但是实现有点儿问题,比较耗时,正在改进中):

用给出的所有点对宝藏点P做线段,找出交点最少的那一组,既是最小开门数。

以上结论需要证明多个推论,证明过程如下:

1、对于任意P,如果和P只间隔一堵墙,那么,P只需要开一扇门

证明:无需证明显而易见。

结论:只要证明墙数,就可以证明门数。

2、边缘上的任意一中点P0对P做线段,交点数等于P到Pi间隔的最小墙数

证明:

  连接P0-P,交点设为N。

  设,存在一条开门路径,连接P0到P,中间穿过了M堵墙。

  可知,P0-P与开门路径之间是封闭的多边形(路径是直线且与P0-P重合不讨论)。

  有定理一:最小完整路径不会两次闯过同一堵墙。(如果有两次闯过,则至少有三个交点A\B\C,连接A-C,则路径更少,易证)

  有定理二:两条子路径之间有且仅有一堵墙(易证,穿过墙只能抵达对侧,不能抵达同侧)

  由定理二可知,墙一定会经过多边形内部,由定理一可知,墙不会再次经过路径,则,墙一定会经过P0-P

  即是M<=N

  

  又有公理一:两条线段最多只有一个交点

  经过了P0-P的线段一定和封闭多边形相交。(由于线段端点落在金字塔边缘,易证)

  即N<=M

  所以M=N。

  

  

  

3、任意现存线段端点与P连线,交点数等于 邻近两个中点分别与P连线 的交点数 中的小值

证明:

  设有两线段L1,L2分别交金字塔外墙为P1,P2,且P1、P2之间再无其他现存线段的交点

  设有一点Pn处于P1,P2之间

  对Pn-P做连线,设有一现存直线Lx,与L1相交,但不与Pn-P相交,则此时满足Pn对P的交点数小于P1。

  此时,Lx与P1-P2外墙的交点,必然落在Pn和P1之间(此点易证),与P1、P2之间无现存线段交点违背。

  可证,Pn-P的交点数一定大于等于P1-P。

  同理可证Pn和P2关系。

  当等于的时候,Pn与P1等价。

  

  当大于的时候,推论如下:

  设有一点Px,Px在Pn-P1延长线上,为P1-P0(P0为另一相交点或者金字塔顶点,相交点等于顶点情况另行讨论)线段上的任意某点。

  

  可知,Px和P1之间再无任意交点。

  那么,沿用先前的推论,P1-P交点数大于等于Px-P0交点数。

  当大于的时候,必有一线段与P1-P相交,不与Px-P0相交,此线段不能落在P1-Px段,只能落在P1-Pn,且不为P1本身(相交非重合),与P1-Pn之间无交点违背。

  所以,必然是等于关系(同理可得L1即是Pn-P多出的那一相交线)

  

  相交点等于顶点情况,如果有P点同侧相交线,相交线必然与金字塔边缘有两个交点,无论落点如何,都能多次引用前半部分推论来同理证得。

  证毕。

结论:

  只需要求线段端点与P的交点数,即可得到最小值。

  

算法:poj1066 宝藏猎人问题。的更多相关文章

  1. PKUWC 2017 Day 2 简要题解

    *注意:题面请移步至loj查看. 从这里开始 Problem A 随机算法 Problem B 猎人杀 Problem C 随机游走 怎么PKU和THU都编了一些假算法,然后求正确率[汗]. 之前听说 ...

  2. PIXI 宝物猎人(7)

    介绍 ,本实例来自官网 代码结构 打开 treasureHunter.html 文件,你将会看到所有的代码都在一个大的文件里.下面是一个关于如何组织所有代码的概览: //Setup Pixi and ...

  3. 2000G电脑大型单机游戏合集

    激活码 游戏名称(ctrl+F查找) 下载链接005875 艾迪芬奇的记忆 游戏下载链接http://pan.baidu.com/s/1t2PYRAj546_1AcOB-khJZg554158 暗影: ...

  4. BFS/DFS算法介绍与实现(转)

    广度优先搜索(Breadth-First-Search)和深度优先搜索(Deep-First-Search)是搜索策略中最经常用到的两种方法,特别常用于图的搜索.其中有很多的算法都用到了这两种思想,比 ...

  5. acm常见算法及例题

    转自:http://blog.csdn.net/hengjie2009/article/details/7540135 acm常见算法及例题  初期:一.基本算法:     (1)枚举. (poj17 ...

  6. ACM算法总结及刷题参考

    参考:http://bbs.byr.cn/#!article/ACM_ICPC/11777 OJ上的一些水题(可用来练手和增加自信)(poj3299,poj2159,poj2739,poj1083,p ...

  7. poj 算法 分类

    转载请注明出处:優YoU http://blog.csdn.net/lyy289065406/article/details/6642573 最近AC题:2528   更新时间:2011.09.22  ...

  8. ACM常用算法及练习(1)

    ACM常用算法及练习 第一阶段:练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码,因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打出来. 1.最短 ...

  9. Tarjan算法求有向图的强连通分量

    算法描述 tarjan算法思想:从一个点开始,进行深度优先遍历,同时记录到达该点的时间(dfn记录到达i点的时间),和该点能直接或间接到达的点中的最早的时间(low[i]记录这个值,其中low的初始值 ...

随机推荐

  1. php namespace用法

    其实纠结了很久要不要使用这个东西,但是看看了最新的框架laravel,cakephp等等的新版本都使用上了,所以还是随大流顺便学习下. namespace和c++里面的概念差不多,只是用法有点差别. ...

  2. REST有状态与无状态的理解

    1. 什么是REST? REST(REpresentation State Transfer)表述性状态传递,是一种软件架构风格,是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可 ...

  3. C#高级--通过类来理解学习委托

    namespace classanddelegate { class Program { static void Main(string[] args) { //这是类的实例化 Test test = ...

  4. ckeditor使用

    安装: 下载CKEDITOR的文件,解压后复制到工程的WEBROOT目录下就OK! 引用CKEDITOR的JS文件: 新建JSP页面,添加其JS文件<script type="text ...

  5. 断言(ASSERT)的用法

    ASSERT ()是一个调试程序时经常使用的宏,在程序运行时它计算括号内的表达式,如果表达式为FALSE (0), 程序将报告错误,并终止执行.如果表达式不为0,则继续执行后面的语句.这个宏通常原来判 ...

  6. kettle(6.0)如何连接远程集群(CDH5.1)?

    最近因为公司业务需要,刚刚接触了kettle.这不看不知道,一看才发现kettle的功能是在是太强大了,让我有种相见恨晚的感觉.由于主要是应用kettle与hadoop集群和hive连接进行数据处理. ...

  7. ulipad源码包配置环境及安装

    一.准备下载的安装包: 1.python(我电脑配置的是2.7)下载地址http://pan.baidu.com/s/1qWrGZk4 2.wxpython(我这里是wxpy3.0,配套python2 ...

  8. C# 部分语法总结(入门经典)

    class Program { static void Main(string[] args) { init(); System.Console.ReadKey(); } #region 接口 /// ...

  9. viewpage 循环滑动播放图片

    一般来说,viewpage 只支持图片的顺序滑动播放,在滑到边界时就再也滑不动了,如果要想继续滑动,只能向两边额外增加一张相片,即把第一张相片的位置放在最后一张图片的后面,给用户的感觉我继续滑就滑到了 ...

  10. 使用DataOutputStream写入int类型数字不能显示

    前段时间做Android系统项目需要使用DataOutputStream数据流向文件里写入数据,写入的有String类型和int类型.写入之后在代码中使用DataInputStream读出是没有问题的 ...