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 ...
随机推荐
- Odoo8中“更多”下拉菜单选项指定后台执行代码
在Odoo8中的仓库模块,根据每日最小安全库存数量,系统会自动生成一些补货单,而且是一个产品会生成一笔,如果产品比较多,这里生成的补货单也会很多. 如果这里的补货单没有即时处理,那相同产品后续不会再生 ...
- 【Python3 爬虫】08_正则表达式(元字符与语法)
元字符表 符号 说明 示例 . 表示任意字符 'abc' >>>'a.c' >>>结果为:'abc' ^ 表示字符开头 'abc' >>> ...
- Activity具体解释(生命周期、启动方式、状态保存,全然退出等)
一.什么是Activity? 简单的说:Activity就是布满整个窗体或者悬浮于其它窗体上的交互界面. 在一个应用程序中通常由多个Activity构成,都会在Manifest.xml中指定一个主的A ...
- C# NPOI操作Excel(上)
NPOI 官网下载DLL:http://npoi.codeplex.com/releases 1.读取Excel转为DataTable /// <summary> /// 读取excel转 ...
- popupwindow从底部弹出
参考了网上的一些代码,自己写了个类,上代码 /** * Created by Lee on 2016/2/26. */ public class CameraPopupWindow { private ...
- Android 四大组件学习之BroadcastReceiver二
上节学习了怎样创建一个广播.也尝试接受系统打电话的广播. 本节课学习怎样自己定义广播.自己定义广播实质上也就是创建一个发送广播者,创建一个接受该广播者. 那我们就開始行动吧. 先创建一个发送广播的应用 ...
- Redis源码之String操作
0.前言 String操作是Redis操作中最基本的类型,包含get,set,mget,mset,append等等.下面我们会具体分析下一些命令的详细流程,特么简单的命令没有列出. 1.SET命令 2 ...
- 在Jboss中使用Quartz
Jboss EJB默认使用的定时服务是TimerService,TimerService的使用过程较为繁琐,需要使用一个无状态的serviceBean去实现scheduleTimer, timeout ...
- Navicat for MySQL 之数据库迁移
1.将数据库下的表迁移出来 2.将表全部迁入另一个数据库 重新连接数据库看看吧!
- ThinkPHP使用PHPExcel实现Excel数据导入导出完整实例
这篇文章主要介绍了ThinkPHP使用PHPExcel实现Excel数据导入导出,非常实用的功能,需要的朋友可以参考下 本文所述实例是使用在Thinkphp的开发框架上,要是使用在其他框架也是同样的方 ...