UVa1318/LA2797 Monster Trap

题目链接

         本题是2003年ICPC亚洲区域赛会津(日本)赛区的H题

题意

        给出一些线段障碍,你的任务是判断怪物能否逃到无穷远处。如下图所示,左图无法逃出,右图的可以逃出。

        输入包含多组数据。每组数据第一行为整数n(1≤n≤100),即线段条数。以下n 行每行4 个整数,即一条线段两端的坐标。假定线段的长度均为正,坐标绝对值不超过50。假设任意两条线段最多只有一个公共点,无三线共点。任意两个交点的距离大于1e-5。输入结束标志为n=0。        

分析

       《训练指南》上的例题,按照其题解做,发现一个套模板的坑点:本题卡阈值!

        这里给出《训练指南》代码仓库上的源码(第10行)来说明坑点:

const double eps = 1e-12;

        如过把eps改为大于1e-12或者小于1e-14的值(比如1e-111e-15)再提交则WA,而eps写成1e-121e-131e-14则AC。

        根本原因在《训练指南》给出的计算几何模板里面的dcmpSegmentProperIntersectionOnSegment三个函数这里。

int dcmp(double x) {return abs(x) < eps ? 0 : (x < 0. ? -1 : 1);
}bool SegmentProperIntersection(const Point& a1, const Point& a2, const Point& b1, const Point& b2) {double c1 = Cross(a2 - a1, b1 - a1), c2 = Cross(a2 - a1, b2 - a1);double c3 = Cross(b2 - b1, a1 - b1), c4 = Cross(b2 - b1, a2 - b1);return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0;
}bool OnSegment(const Point& p, const Point& a1, const Point& a2) { // 不含端点return dcmp(Cross(a1 - p, a2 - p)) == 0 && dcmp(Dot(a1 - p, a2 - p)) < 0;
}

        OnSegment函数对dcmp的阈值eps要求低一些(不可太大也不可太小,中间范围即可),但本题的做法涉及把每条线段两端延长一点点(按题意延长量为1e-6合适,因为题木交代两个交点的距离在1e-5量级以上),这样就导致SegmentProperIntersection里面叉乘的结果可能很小,极端数据会小于eps。

        说一下解决方案:SegmentProperIntersection里面对叉乘直接判断符号,不用阈值。

int sign(double x) {return x==0. ? 0 : (x < 0. ? -1 : 1);
}bool SegmentProperIntersect(const Point& a1, const Point& a2, const Point& b1, const Point& b2) {double c1 = Cross(a2 - a1, b1 - a1), c2 = Cross(a2 - a1, b2 - a1);double c3 = Cross(b2 - b1, a1 - b1), c4 = Cross(b2 - b1, a2 - b1);// return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0;// 部分卡精度的题目需要直接判断正负号return sign(c1) * sign(c2) < 0 && sign(c3) * sign(c4) < 0;
}

        附一份测试数据和用python写的画图可视化分析数据的脚本方便读者debug。

AC代码

#include <iostream>
#include <cstring>
#include <cmath>
#include <map>
using namespace std;#define eps 1e-10
struct Point {double x, y;Point(double x = 0, double y = 0): x(x), y(y) {}void Normalize() {double l = sqrt(x*x + y*y); x /= l; y /= l;}
};
typedef Point Vector;Vector operator+ (const Vector& A, const Vector& B) {return Vector(A.x + B.x, A.y + B.y);
}Vector operator- (const Vector& A, const Vector& B) {return Vector(A.x - B.x, A.y - B.y);
}Vector operator* (const Vector& A, double p) {return Vector(A.x * p, A.y * p);
}bool operator< (const Point& a, const Point& b) {return a.x < b.x || (a.x == b.x && a.y < b.y);
}double Cross(const Vector& A, const Vector& B) {return A.x * B.y - A.y * B.x;
}double Dot(const Vector& A, const Vector& B) {return A.x * B.x + A.y * B.y;
}int dcmp(double x) {return abs(x) < eps ? 0 : (x < 0. ? -1 : 1);
}int sign(double x) {return x==0. ? 0 : (x < 0. ? -1 : 1);
}bool SegmentProperIntersect(const Point& a1, const Point& a2, const Point& b1, const Point& b2) {double c1 = Cross(a2 - a1, b1 - a1), c2 = Cross(a2 - a1, b2 - a1);double c3 = Cross(b2 - b1, a1 - b1), c4 = Cross(b2 - b1, a2 - b1);return sign(c1) * sign(c2) < 0 && sign(c3) * sign(c4) < 0;
}bool OnSegment(const Point& p, const Point& a1, const Point& a2) {return dcmp(Cross(a1 - p, a2 - p)) == 0 && dcmp(Dot(a1 - p, a2 - p)) < 0;
}#define N 205
Point p[N]; int x[N], q[N], n, t; bool vis[N];bool NotOnAnySegment(const Point& x) {for (int i=0; i<n; ++i) if (OnSegment(x, p[i], p[i+n])) return false;return true;
}bool NotIntersectWithAnySegment(int u, int v) {for (int i=0; i<n; ++i) if (SegmentProperIntersect(p[i], p[i+n], p[u], p[v])) return false;return true;
}bool solve() {memset(vis, t = 0, sizeof(vis));for (int i=0; i<n; ++i) {cin >> p[i].x >> p[i].y >> p[i+n].x >> p[i+n].y;Vector v = p[i+n] - p[i]; v.Normalize(); v = v*1e-6;p[i].x -= v.x; p[i].y -= v.y; p[i+n].x += v.x; p[i+n].y += v.y;}p[n<<1].x = p[n<<1].y = 0.; p[(n<<1)+1].x = -60.; p[(n<<1)+1].y = 60.; x[t++] = n<<1; x[t++] = (n<<1)+1;for (int i=0; i<n; ++i) {if (NotOnAnySegment(p[i])) x[t++] = i;if (NotOnAnySegment(p[i+n])) x[t++] = i+n;}int head = 0, tail = 1; q[0] = 0;while (head < tail) {int u = q[head++];for (int v=1; v<t; ++v) if (!vis[v] && NotIntersectWithAnySegment(x[u], x[v])) {if (v == 1) return false;vis[q[tail++] = v] = 1;}}return true;
}int main() {ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);while (cin >> n && n) cout << (solve() ? "yes" : "no") << endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/415545.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

zabbix其他配置

自动发现 zabbix server 主动的去发现所有的客户端&#xff0c;然后将客户端的信息登记在服务端上。 缺点是如果定义的网段中的主机数量多&#xff0c;zabbix server 登记耗时较久&#xff0c;且压力会较大。 systemctl disable --now firewalld setenforce 0 hostnamectl se…

【unity学习笔记】语音驱动blendershape

1.导入插件 https://assetstore.unity.com/packages/tools/animation/salsa-lipsync-suite-148442 1.选择小人&#xff0c;点击添加组件 分别加入组件&#xff1a; SALSA EmoteR Eyes Queue Processor&#xff08;必须加此脚本&#xff09;&#xff1a;控制前三个组件的脚本。…

vulnhub靶机Chill_Hack

下载地址&#xff1a;Chill Hack: 1 ~ VulnHub 主机发现 目标176 端口扫描 服务扫描 直接去看web 先扫一下 有几个有点问题 看着好像命令执行 看来没错直接反弹shell 还有还白名单&#xff1f; bash也不能用 那就用php吧 whoami|php -r $sockfsockopen("192.168.21.13…

微信这个费用,终于降低了

大家好&#xff0c;我是小悟 这个费用降低了&#xff0c;这对于广大小程序开发者来说无疑是一个好消息。这一举措不仅可以降低开发者的成本&#xff0c;还有助于激发更多的创新和创业激情。 对于广大小程序开发者来说&#xff0c;这也是一个福音&#xff0c;因为他们可以降低开…

使用 Jest 和 Supertest 进行接口端点测试实例详解

如何创建测试是一件困难的事。网络上有许多关于测试的文章&#xff0c;却从来不告诉你他们是如何开始创建测试的。 所以&#xff0c;今天我将分享我在实际工作中是如何从头开始创建测试的。希望能够对你提供一些灵感。 目录&#xff1a; 使用 Express 创建一个应用 使用 Mon…

Mysql:重点且常用的操作和理论知识整理 ^_^

目录 1 基础的命令操作 2 DDL 数据库定义语言 2.1 数据库操作 2.2 数据表操作 2.2.1 创建数据表 2.2.2 修改和删除数据表 2.2.3 添加外键 3 DML 数据库操作语言 3.1 插入语句(INSERT) 3.2 修改语句(UPDATE) 3.3 删除语句 3.3.1 DELETE命令 3.3.2 TRUNCATE命令 4 …

vue基于Spring Boot共享单车租赁报修信息系统

共享单车信息系统分为二个部分&#xff0c;即管理员和用户。该系统是根据用户的实际需求开发的&#xff0c;贴近生活。从管理员处获得的指定账号和密码可用于进入系统和使用相关的系统应用程序。管理员拥有最大的权限&#xff0c;其次是用户。管理员一般负责整个系统的运行维护…

【文本到上下文 #5】:RNN、LSTM 和 GRU

一、说明 欢迎来到“完整的 NLP 指南&#xff1a;文本到上下文 #5”&#xff0c;这是我们对自然语言处理 &#xff08;NLP&#xff09; 和深度学习的持续探索。从NLP的基础知识到机器学习应用程序&#xff0c;我们现在深入研究了神经网络的复杂世界及其处理语言的深刻能力。 在…

BACCM业务模型核心概念

业务分析概念一览 现在&#xff0c;我们将商业&#xff08;业务&#xff09;分析核心概念模型™&#xff08;BACCM™&#xff09;中六个核心概念&#xff08;core concept&#xff09;整理如下&#xff1a; Change&#xff0c;the act of transformation in response to a nee…

FaFu--练习复盘--1

1、输出图形及二维数组应用 1.1.输出图形 描述 编写程序打印n行如下图形&#xff0c;其中1≤n≤500。 输入用例 7 输出用例 具体实现 #include"stdio.h" int main(){int n,i,j;scanf("%d",&n);for(i 1; i< n;…

mysql-实战案例 (超详细版)

&#x1f389;欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克&#x1f379; ✨博客主页&#xff1a;小小恶斯法克的博客 &#x1f388;该系列文章专栏&#xff1a;重拾MySQL &#x1f379;文章作者技术和水平很有限&#xff0c;如果文中出现错误&am…

Linux粘滞位的理解,什么是粘滞位?

文章目录 前言如何理解&#xff1f;粘滞位的操作最后总结一下 前言 粘滞位&#xff08;Stickybit&#xff09;&#xff0c;或粘着位&#xff0c;是Unix文件系统权限的一个旗标。最常见的用法在目录上设置粘滞位&#xff0c;如此以来&#xff0c;只有目录内文件的所有者或者root…