poj 1039
2016-07-25 21:53
399 查看
题目概述
有一种管线,横截面是上下平行的两根折线,在坐标系中,两根折线上横坐标相等的点,其纵坐标相差1,管线不透光,不反光,但拐点处不会阻挡光,现有一束光从管线最左侧开口处射入,给定管线上部各点坐标,问光能否贯穿整条管线,若不能,求出其最远到达位置的横坐标时限
1000ms/3000ms输入
第一行正整数N,代表管线上部共N个端点,其后N行,每行两个浮点数,描述管线上部各端点位置,输入到N=0结束限制
2<=N<=20输出
每组数据输出在一行中,若可贯穿,则输出字符串Through all the pipe.
否则输出一保留两位的浮点数,为所求最远位置的横坐标
样例输入
40 1
2 2
4 1
6 4
6
0 1
2 -0.6
5 -4.45
7 -5.57
12 -10.8
17 -16.55
4
-7 1
-5 2
-3 1
-1 4
0
样例输出
4.67Through all the pipe.
-2.33
讨论
计算几何,直线与线段位置关系,首先一定要注意,题目可没说横坐标不能全是负的,额初始化most=0.0直接贡献一WA,主要的实现,看过刘汝佳黑书的应该能知道(额没看过,看别人的解法才知道),走的最远的光线一定经过上下折线各一个端点,这和poj 3304有异曲同工之妙,并且判断最远位置时,仅需要判断是否和某上下一对端点所成线段相交即可,若不相交,则求光线与这对端点左侧的那两条线段的交点横坐标,取较大者即可,结合上面两条,再加上一点,光肯定是要经过起点的,如果都无法经过最左侧两个端点所成线段,那又哪来的光呢,这样基本思路也就明晰了判断是否和上下端点所成线段相交是一个非常明智的转化做法,因为题目说端点并不会阻挡光,但若直接枚举每条线段则必然要判断光是擦过拐点还是撞上管壁,这需要端点前后两条线段分别和光的端点做向量积得到(在同侧则撞上,在异侧则擦过),但最后一对端点都没有下一条线段,因而还需要特殊处理,仅仅考虑至此,代码已经非常复杂了,其实还有其他一些小地方也需要处理,就不再枚举了
题解状态
192K,47MS,C++,1777B题解代码
#include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; #define INF 0x3f3f3f3f #define MAXN 41 #define memset0(a) memset(a,0,sizeof(a)) #define EPS 1e-6 int N;//端点数的一半 double x[MAXN], y[MAXN];//端点横纵坐标 double xp(double x1, double y1, double x2, double y2, double x3, double y3) { return (x1 - x2)*(y3 - y2) - (y1 - y2)*(x3 - x2); } bool intersect(double x1, double y1, double x2, double y2, double x3, double y3, double< d69c /span> x4, double y4) { return xp(x3, y3, x1, y1, x2, y2)*xp(x4, y4, x1, y1, x2, y2) <= EPS; }//直线与线段相交的两大函数 在之前的题中介绍过无数次了 double point_of_intersection_x(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)//交点横坐标 由于只求横坐标 因而没有斜率的情况方便不少 { if (abs(x1 - x2) < EPS) return x1; if (abs(x3 - x4) < EPS) return x3; else { double k1 = (y2 - y1) / (x2 - x1); double k3 = (y4 - y3) / (x4 - x3); return ((y3 - y1) + k1*x1 - k3*x3) / (k1 - k3); } } void fun() { for (int p = 0; p < N; p++) { scanf("%lf%lf", &x[p], &y[p]);//input x[N + p] = x[p], y[N + p] = y[p] - 1;//下部的从下标N开始 } double most = -INF;//详见第三组样例数据 for (int p = 0; p < N; p++)//枚举一个上点 for (int i = N; i < 2 * N; i++) {//枚举一个下点 if (!intersect(x[p], y[p], x[i], y[i], x[0], y[0], x , y )) continue;//没过起点 没戏 bool f = 1;//光没有与任何管壁X型相交的标记 for (int u = 1; u < N; u++) {//枚举上下一对的点所成线段 if (!intersect(x[p], y[p], x[i], y[i], x[u], y[u], x[u + N], y[u + N])) {//遇到没有相交的 most = max(most, point_of_intersection_x(x[p], y[p], x[i], y[i], x[u], y[u], x[u - 1], y[u - 1]));//求与上部交点并取最大值 most = max(most, point_of_intersection_x(x[p], y[p], x[i], y[i], x[u + N], y[u + N], x[u - 1 + N], y[u - 1 + N]));//求与下部交点并取最大值 f = 0;//与管壁相撞过了 break;//光不会再前进了 } } if (f) {//如果光直接贯穿管线 printf("Through all the pipe.\n");//output return; } } printf("%.2lf\n", most);//output } int main(void) { //freopen("vs_cin.txt", "r", stdin); //freopen("vs_cout.txt", "w", stdout); while (~scanf("%d", &N) && N) //input fun(); }
EOF
相关文章推荐
- Git自学之路(三)- Git打标签
- ABAP中对变式的处理
- 二叉树的序列化和反序列化
- Subsequence(hdu 3530)
- 信息安全管理(4):信息安全系统的技术规范模型
- 朴素的完全背包
- 正则表达式介绍及常见用法
- Hibernate 入门示例
- 4632 NOIP[2015] 运输计划
- Hibernate学习笔记----Session管理和批量操作
- java设计模式_原型模式
- 使用SpringMVC实现文件上传功能
- Exception in thread "main" java.lang.AbstractMethodError: weblogic.server.channels.ServerChannelImpl
- [状态机]嵌入式设计模式:有限状态自动机的C语言实现
- 如何使用SAP发送邮件?
- JDNI学习总结(一)
- 大数据基础(六) Matlab R2015b MDCE分布式计算环境搭建
- IntelliJ IDEA应用第一步
- 数据结构 -- 红黑树
- MongoDB 3.2配置文件directoryPerDB参数,无法重启