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 ...
随机推荐
- Js中数组的追加
Concat arrayObject.concat(arrayX,arrayX,......,arrayX) 常用于 加载更多 ,数组的追加.
- EXTJS4自学手册——图形行为(rotate,scale)
一.旋转图像: { xtype: 'button', text: '旋转的字', handler: function (btn) { Ext.create('Ext.window.Window', { ...
- mysql 5.6的安装
MySQL安装 yum install -y perl-Module-Install.noarch cd /usr/local/src wget http://mirrors.sohu.com/m ...
- 今日头条&58转转笔试
昨天参加今日头条和58转转的笔试,因为时间上有冲突,所以主要选择参加头条的笔试. 先说头条: 头条的题型: 一道改错题 三道编程题 一道设计题 感受: 做题目的的时候还是有点紧张的,因为突然遇到题目需 ...
- android studio - 隐藏编辑器上面的竖线
android studio 的代码编辑器上面默认有一条竖线不知道是干什么用的,很难看.可以用下列方法进行隐藏. 取消选中这个复选框即可.
- MAJOR-MINOR-MKDEV
标记一下,容易忘,以免每次查代码. ./include/linux/types.h:21:typedef __u32 __kernel_dev_t; ./include/linux/types.h:2 ...
- 服务器上nginx反向代理的配置
Nginx不但是一款高性能的Web服务器,也是高性能的反向代理服务器.下面简单说说Nginx的反向代理功能. 反向代理是什么? 反向代理指以代理服务器来接受Internet上的连接请求,然后将请求转发 ...
- FreeBSD中实现root的ssh
在虚拟机中刚装好FreeBSD,结果不能以远程方式登录root,然后在如下链接中找到了解决方法: http://blog.chinaunix.net/uid-26719405-id-3822697.h ...
- 查看文件内容- 删除某个运行程序的所有进程-nohup后台执行程序
1 查看文件内容: tail -f test.txt 2 查看端口 netstat nlp 3 删除某个运行程序的所有进程 ps -ef|grep translateService.py|grep - ...
- imx6用文件io操作gpio
具体请参考: http://blog.csdn.net/u014213012/article/details/53140781 这里要注意的是: 要让linux支持文件io方式操作gpio,首先驱动必 ...