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 ...
随机推荐
- IEEE会议投稿资料汇总http://cadcg2015.nwpu.edu.cn/index.htm
近期投了篇IEEE的顶级会议文章,一下是比較实用的一些资料,以供參考. 1.会议主页:http://cadcg2015.nwpu.edu.cn/index.htm (The 14th Inte ...
- Android Exception 17(database or disk is full)
android.database.sqlite.SQLiteFullException: database or disk is full delete some app,or clear cache
- Apache代理80端口
找到Apache下的conf\extra\httpd-vhosts.conf文件 新增以下内容于合适位置 ↓表示80端口 <VirtualHost *:80> ServerAdmin * ...
- [1-5] 把时间当做朋友(李笑来)Chapter 5 【小心所谓成功学】 摘录
有一个事实非常简单,却令人难以接受.这世界上所有的资源并非平均分布在每一个人的身上,能够比较接近地表示这种分布情况的数学曲线叫做“正态分布曲线”(Normal Distribution Curve) ...
- JavaScript之变量、作用域和内存问题
js中的变量可能包含2种数据类型,基础数据类型和引用数据类型. 一般而言,基本数据类型是数据段,引用数据类型是对象. 保存方式的不同: 基本类型可以直接操作保存在变量中的值:而引用类型真实的值是保存在 ...
- oracle导出表的办法
1.先进行表分析(一定要执行此步,否则查询空表可能不准确) select 'analyze table '||table_name||' compute statistics;' from user_ ...
- 修改PHP session 默认时间方法
修改三行如下: 1.session.use_cookies把这个的值设置为1,利用cookie来传递sessionid 2.session.cookie_lifetime这个代表SessionID在客 ...
- hdu3208 Power of Integer
/** 题目:H - Power of Integer 链接:https://vjudge.net/contest/152887#problem/H 题意:给出区间[a, b],问你区间[a, b]所 ...
- MySQL 5.7以上 root用户默认密码问题
废话少说一句话系列: CentOS系统用yum安装MySQL的朋友,请使用 grep "temporary password" /var/log/mysqld.log 命令,返回结 ...
- fedora上安装sun jdk
系统被来就有openjdk,但是开发工具需要sun的jdk,于是下载一个压缩包并解压到一个位置.使用alternative命令切换 alternatives --.0_79/jre/bin/java ...