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 ...
随机推荐
- POJ 3221 Diamond Puzzle(BFS)
Description A diamond puzzle is played on a tessellated hexagon like the one shown in Figure 1 below ...
- c与c++中的强制类型转换区别
强制类型转换的一般形式为: (类型名)(表达式) 如:(int)a.这是C语言使用的形式,C++把它保留了下来,以利于兼容. C++还增加了以下形式: 类型名(表达式) 如:int(a).这种形式类似 ...
- kvaser leaf light v2 在Linux 下面的使用方法
一.安装驱动 下载地址: https://www.kvaser.cn/developer-blog/build-install-signed-kvaser-driver-modules/ 严格按照操 ...
- BASE64Decoder的引用
project---->properties--->Libraries--->JRE System Library--->Access rules--->Edit---& ...
- Mysql 常用函数集
1.分类导航 一共分为5类函数 . 字符型函数 . 数值型函数 . 日期型函数 . 统计型函数 . 其它型函数 2.字符型函数[约48个] ascii(str) bin(n) bit_length(s ...
- iptables修改
https://fedoraproject.org/wiki/How_to_edit_iptables_rules?rd=User_talk:Rforlot Listing Rules Current ...
- JAVA 利用SimpleDateFormat将String转换为格式化的日期
1. /** * 使用用户格式提取字符串日期 * * @param strDate 日期字符串 * @param pattern 日期格式 * @return */ public static Dat ...
- 微信小程序注册开发流程
开篇: 微信小程序 很多刚学的同学都不太清楚如何去申请这个小程序的appid 现在呢我就一步步的告诉大家这个流程: 首先第1步,百度搜索:微信公众平台-点击右上角的立即注册 第2步:可以看到有4大注册 ...
- crontab用法
在工作中有时需要定时执行某些操作,于是想到使用crontab来实现 crontab的用法: crontab file [-u user] 用指定的文件替代目前的crontab crontab - ...
- 树莓派、 Arduino 、传统单片机开发板该如何选择?
几十年前的电子爱好者,最喜欢的就是电烙铁.面包板和收音机:十几年前,出现了单片机,于是玩具就成了电烙铁.面包板和单片机:到了2015年,贴片技术的不断普及,让面包板不再那么有用武之地,经济的发展也让现 ...