poj 1039
来源:互联网 发布:python split 多个 编辑:程序博客网 时间:2024/06/03 19:21
题目概述
有一种管线,横截面是上下平行的两根折线,在坐标系中,两根折线上横坐标相等的点,其纵坐标相差1,管线不透光,不反光,但拐点处不会阻挡光,现有一束光从管线最左侧开口处射入,给定管线上部各点坐标,问光能否贯穿整条管线,若不能,求出其最远到达位置的横坐标
时限
1000ms/3000ms
输入
第一行正整数N,代表管线上部共N个端点,其后N行,每行两个浮点数,描述管线上部各端点位置,输入到N=0结束
限制
2<=N<=20
输出
每组数据输出在一行中,若可贯穿,则输出字符串
Through all the pipe.
否则输出一保留两位的浮点数,为所求最远位置的横坐标
样例输入
4
0 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.67
Through 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-6int 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 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[N], y[N])) 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
- poj 1039
- poj 1039
- poj 1039
- poj 1039
- POJ 1039 Pipe
- POJ 1039 Pipe
- POJ 1039 Pipe
- POJ 1039 Pipe
- POJ 1039 Pipe
- POJ 1039 Pipe
- POJ 1039 Pipe
- POJ 1039 Pipe
- poj 1039 Pipe
- POJ 1039 pipe
- POJ 1039--Pipe
- poj 1039 Pipe
- Pipe - POJ 1039 几何
- POJ 1039 Pipe
- 使用SpringMVC实现文件上传功能
- java设计模式_原型模式
- Docker数据管理:Named volume
- ABAP中对变式的处理
- 向手机磁盘存数据利用SharedPreferences
- poj 1039
- AngularJS 简介
- 网络基础知识点总结1
- 数组的函数传递的两种方式(数组名和指针)
- Markdown书写博客
- JS变量提升、匿名函数、原型继承、作用域、闭包机制等。
- Linux->openSUSE->Input method
- Android中的基础----Handler、Looper、MessageQueue的工作原理
- python函数式编程