POJ 1039 Pipe【经典线段与直线相交】
链接:
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 8350 | Accepted: 2501 |
Description
Note that the material which the pipe is made from is not transparent and not light reflecting.
Each pipe component consists of many straight pipes connected tightly together. For the programming purposes, the company developed the description of each component as a sequence of points [x1; y1], [x2; y2], . . ., [xn; yn], where x1 < x2 < . . . xn . These
are the upper points of the pipe contour. The bottom points of the pipe contour consist of points with y-coordinate decreased by 1. To each upper point [xi; yi] there is a corresponding bottom point [xi; (yi)-1] (see picture above). The company wants to find,
for each pipe component, the point with maximal x-coordinate that the light will reach. The light is emitted by a segment source with endpoints [x1; (y1)-1] and [x1; y1] (endpoints are emitting light too). Assume that the light is not bent at the pipe bent
points and the bent points do not stop the light beam.
Input
with n = 0.
Output
the pipe.. The real value is the desired maximal x-coordinate of the point where the light can reach from the source for corresponding pipe component. If this value equals to xn, then the message Through all the pipe. will appear in the output file.
Sample Input
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
0
Sample Output
4.67
Through all the pipe.
Source
题意:
如果不能完整通过,则输出最远的相交点【x 最大】
算法:直线与线段相交【叉积】
思路:
看是否合法,如果合法:那么再看是否能够通过整个通道
如果不能通过,则输出最远的 X
注意:
【有可能光线早就跑到了管道外面,而你判断的确是没有交点,
最后结果就变成了光线通过了整个通道,但是事实却并不是这样】
所以,必须让光线和挡板【上下端点所成直线】相交,来确定光线确实在管道内
/** 叉积*/
double Cross(Point A, Point B){
return A.x*B.y - A.y*B.x;
} /** Segment l1 cross Line l2*/
bool SegmentCrossLine(Line l1, Line l2) //Segment l1 cross Line l2
{
return Cross(l1.s-l2.s,l2.e-l2.s)*Cross(l2.e-l2.s,l1.e-l2.s) > 0;
}
Through all the pipe.
/*************************************************************
B Accepted 192 KB 47 ms C++ 2744 B
题意:给你一个管道,问是否能有这样一条光线从左到右边完整通过
如果不能完整通过,则输出最远的相交点【x 最大】
算法:直线与线段相交【叉积】
思路:枚举上下端点成光线所在的直线即可
看是否合法,如果合法:那么再看是否能够通过整个通道
如果不能通过,则输出最远的 X
注意:判断线段和直线相交时,不能直接用两个叉积的积来判断
【有可能光线早就跑到了管道外面,而你判断的确是没有交点,
最后结果就变成了光线通过了整个通道,但是事实却并不是这样】
所以,必须让光线和挡板【上下端点所成直线】相交,来确定光线确实在管道内
**************************************************************/
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std; const int maxn = 30;
const double DNF = 100000000;
int n;
double ans; struct Point{
double x,y;
Point() {}
Point(double _x, double _y) {
x = _x;
y = _y;
} Point operator + (const Point &B) const {
return Point(x+B.x, y+B.y);
}
Point operator - (const Point &B) const {
return Point(x-B.x, y-B.y);
}
Point operator * (const double &p) const {
return Point(p*x, p*y);
}
bool operator == (const Point &B) const {
return x == B.x && y == B.y;
}
}up[maxn],down[maxn];
typedef Point Vector; double Cross(Point A, Point B){
return A.x*B.y - A.y*B.x;
}
/** 求直线 P+tv 和直线 Q+tw的交点 */
Point GetLineIntersection(Point P, Vector v, Point Q, Vector w){
Vector u = P-Q;
double t = Cross(w,u) / Cross(v,w);
return P+v*t;
} /** 精度判断 */
const double eps = 1e-5;
int dcmp(double x)
{
if(fabs(x) < eps) return 0;
else return x < 0 ? -1 : 1;
} /** 检查直线 AB , 当前光线在第 e 段通道确定 */
bool check(Point A, Point B, int e){
int sign = 0;
int i;
for(i = 1; i < n; i++)
{
if(dcmp(Cross(B-A, up[i]-A)) < 0 || dcmp(Cross(B-A,up[i+1]-A)) < 0)
{//判断直线 AB 与线段 up[i] —— up[i+1]是否相交【注意】
sign = 1; break;
} if(dcmp(Cross(B-A,down[i]-A)) > 0 || dcmp(Cross(B-A,down[i+1]-A)) > 0 )
{//判断直线 AB 与线段 down[i]——down[i+1]是否相交【注意】
sign = 2; break;
} }
if(i < e) return false; //光线不合法
if(i == n) return true; //通过整条通道
//求最远的 x
Point InterPoint;
if(sign == 1) //与管道上面的线段相交
{
InterPoint = GetLineIntersection(A,A-B,up[i],up[i]-up[i+1]);
}
else if(sign == 2) //与管道下面的线段相交
{
InterPoint = GetLineIntersection(A,A-B,down[i],down[i]-down[i+1]);
}
//if(InterPoint == up[n] || InterPoint == down[n]) return true;
ans = max(ans,InterPoint.x);
return false; } int main()
{
while(scanf("%d", &n) != EOF)
{
if(n == 0) break; double x,y;
for(int i = 1; i <= n; i++)
{
scanf("%lf%lf", &x, &y);
up[i] = Point(x,y);
down[i] = Point(x,y-1);
} ans = -DNF;
int flag = 0; //标记是否能通过整条通道
if(n < 3) flag = 1;
for(int i = 1; i <= n && !flag; i++)
{
for(int j = i+1; j <= n; j++)
{
flag = check(up[i],down[j],i);
if(flag) break;
flag = check(down[i],up[j],i);
if(flag) break;
}
if(flag) break;
}
if(flag) printf("Through all the pipe.\n");
else printf("%.2lf\n", ans);
}
return 0;
}
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
#include <set>
#include <string>
#include <math.h> using namespace std; const double eps = 1e-8;
int sgn(double x)
{
if(fabs(x) < eps)return 0;
if(x < 0)return -1;
else return 1;
}
struct Point
{
double x,y;
Point(){}
Point(double _x,double _y)
{
x = _x;y = _y;
}
Point operator -(const Point &b)const
{
return Point(x - b.x,y - b.y);
}
//叉积
double operator ^(const Point &b)const
{
return x*b.y - y*b.x;
}
//点积
double operator *(const Point &b)const
{
return x*b.x + y*b.y;
}
void input()
{
scanf("%lf%lf",&x,&y);
}
};
struct Line
{
Point s,e;
Line(){}
Line(Point _s,Point _e)
{
s = _s;e = _e;
}
//两直线相交求交点
//第一个值为0表示直线重合,为1表示平行,为0表示相交,为2是相交
//只有第一个值为2时,交点才有意义
pair<int,Point> operator &(const Line &b)const
{
Point res = s;
if(sgn((s-e)^(b.s-b.e)) == 0)
{
if(sgn((s-b.e)^(b.s-b.e)) == 0)
return make_pair(0,res);//重合
else return make_pair(1,res);//平行
}
double t = ((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));
res.x += (e.x-s.x)*t;
res.y += (e.y-s.y)*t;
return make_pair(2,res);
}
};
//判断直线和线段相交
bool Seg_inter_line(Line l1,Line l2) //判断直线l1和线段l2是否相交
{
return sgn((l2.s-l1.e)^(l1.s-l1.e))*sgn((l2.e-l1.e)^(l1.s-l1.e)) <= 0;
} Point up[100],down[100];
int main()
{
int n;
while(scanf("%d",&n) == 1 && n)
{
for(int i = 0;i < n;i++)
{
up[i].input();
down[i] = up[i];
down[i].y -= 1;
}
bool flag = false;//穿过所有的标记
double ans = -10000000.0;
int k;
for(int i = 0;i < n;i++)
{
for(int j = i+1;j < n;j++)
{
//判断直线 up[i]——down[j]
for(k = 0;k < n;k++) //判断是否跑到管道外面,应该和前面的所有的挡板相交
if(Seg_inter_line(Line(up[i],down[j]),Line(up[k],down[k])) == false)
break;
if(k >= n) //通过了所有的挡板,光线可以射穿管道
{
flag = true;
break;
}
if(k > max(i,j)) //如果光线合法
{
if(Seg_inter_line(Line(up[i],down[j]),Line(up[k-1],up[k])))
{
pair<int,Point>pr = Line(up[i],down[j])&Line(up[k-1],up[k]);
Point p = pr.second;
ans = max(ans,p.x);
}
if(Seg_inter_line(Line(up[i],down[j]),Line(down[k-1],down[k])))
{
pair<int,Point>pr = Line(up[i],down[j])&Line(down[k-1],down[k]);
Point p = pr.second;
ans = max(ans,p.x);
}
} //判断直线 down[i]——up[j]
for(k = 0;k < n;k++)
if(Seg_inter_line(Line(down[i],up[j]),Line(up[k],down[k])) == false)
break;
if(k >= n)
{
flag = true;
break;
}
if(k > max(i,j))
{
if(Seg_inter_line(Line(down[i],up[j]),Line(up[k-1],up[k])))
{
pair<int,Point>pr = Line(down[i],up[j])&Line(up[k-1],up[k]);
Point p = pr.second;
ans = max(ans,p.x);
}
if(Seg_inter_line(Line(down[i],up[j]),Line(down[k-1],down[k])))
{
pair<int,Point>pr = Line(down[i],up[j])&Line(down[k-1],down[k]);
Point p = pr.second;
ans = max(ans,p.x);
}
}
}
if(flag)break;
}
if(flag)printf("Through all the pipe.\n");
else printf("%.2lf\n",ans);
}
return 0;
}
POJ 1039 Pipe【经典线段与直线相交】的更多相关文章
- POJ 1039 Pipe 枚举线段相交
Pipe Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 9493 Accepted: 2877 Description ...
- 判断线段和直线相交 POJ 3304
// 判断线段和直线相交 POJ 3304 // 思路: // 如果存在一条直线和所有线段相交,那么平移该直线一定可以经过线段上任意两个点,并且和所有线段相交. #include <cstdio ...
- 简单几何(直线与线段相交) POJ 1039 Pipe
题目传送门 题意:一根管道,有光源从入口发射,问光源最远到达的地方. 分析:黑书上的例题,解法是枚举任意的一个上顶点和一个下顶点(优化后),组成直线,如果直线与所有竖直线段有交点,则表示能穿过管道. ...
- POJ 1039 Pipe(直线和线段相交判断,求交点)
Pipe Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 8280 Accepted: 2483 Description ...
- poj 3304线段与直线相交
http://poj.org/problem?id=3304 Segments Time Limit: 1000MS Memory Limit: 65536K Total Submissions: ...
- poj 3304 Segments 线段与直线相交
Segments Time Limit: 1000MS Memory Limit: 65536K Description Given n segments in the two dim ...
- POJ - 1039 Pipe(计算几何)
http://poj.org/problem?id=1039 题意 有一宽度为1的折线管道,上面顶点为(xi,yi),所对应的下面顶点为(xi,yi-1),假设管道都是不透明的,不反射的,光线从左边入 ...
- poj 1039 Pipe(几何基础)
Pipe Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 9932 Accepted: 3045 Description ...
- poj 1410 Intersection (判断线段与矩形相交 判线段相交)
题目链接 Intersection Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 12040 Accepted: 312 ...
随机推荐
- C/C++获取当前系统时间
个人觉得第二种还是比较实用的,而且也是最常用的~ 不过当计算算法耗时的时候,不要忘记second,不能只要用Milliseconds来减,不然后出现负值,若是算法耗时太长就得用minutes啦.再不然 ...
- react 的死循环
在 componentWillUpdate 中 通过 this.setState 修改状态值,可能会导致死循环,因为会调用 shouldComponentUpdate 可以通过 nextProp.pr ...
- socket websocket
1.websocket客户端 websocket允许通过JavaScript建立与远程服务器的连接,从而实现客户端与服务器间双向的通信.在websocket中有两个方法: 1.send() 向远程服务 ...
- CentOS6.5内核升级到linux 3.12.17教程
环境: 系统硬件:vmware vsphere (CPU:2*4核,内存2G) 系统版本:Linux centos 2.6.32-431.el6.x86_64(Centos-6.5-x86_64-mi ...
- js常用工具
1.反编译工具 .NET Reflector 2.js检查工具 ReSharper 8.0.14.856 官方原版+注册机 JScript Editor Extensions JSEn ...
- python判断文件是否存在目录中
##支持排除文件和目录#!/usr/bin/python #coding:utf-8 import os def list_file(file_name): data = [] file_name = ...
- GoogLeNet模型的微调
我从零开始训练了GoogLeNet模型. 但它没有给我带来希望的结果. 作为替代,我想对我的数据集中的GoogLeNet模型进行微调. 有谁知道我应该遵循什么步骤? 采纳答案: 假设你正在尝试做图像分 ...
- 利用Python读取文件名并生成txt文件——以图片文件为例
效果如下: 代码: import os class ReadImageName(): def __init__(self): self.path = '.' def readname(self): f ...
- deepin下安装python的Tkinter库
在Linux下,如果需要编写界面应用,并且此界面应用对性能的要求不是很高,一般可以使用Python解决.Python中可以使用自带的Tkinter库或者是第三方的Wxpython库,当然Tkinter ...
- Tomcat启动报错:SERVER: Error ListenerStart 排查过程记录
报错的Tomcat截图: 要排查此问题,首先需要调整tomcat的日志级别,调整成通过log4j来记录日志的方式,具体的调整方式: http://tomcat.apache.org/tomcat- ...