POJ:2074

题目链接:http://poj.org/problem?id=2074

把每个线段挡住的区间求出来,删去不合法的部分,合并重叠的部分。

这题dubug了好久,多亏了大佬给出的测试样例^-^,放文后了

#include  <map>
#include  <set>
#include  <cmath>
#include  <queue>
#include  <cstdio>
#include  <vector>
#include  <climits>
#include  <cstring>
#include  <cstdlib>
#include  <iostream>
#include  <algorithm>
using namespace std;
const double pi = acos(-1.0);
const double inf = 1e100;
/*
误差判断
*/
const double eps = 1e-9;
int dcmp(double x, double y){
    if(fabs(x - y) < eps)
        return 0;
    if(x > y)
        return 1;
    return -1;
}
int sgn(double d){
    if(fabs(d) < eps)
        return 0;
    if(d > 0)
        return 1;
    return -1;
}
/*---------------------------------------------------------------------------------------*/
//点
struct Point{
	double x, y,z;
    Point(double x = 0, double y = 0, double z = 0):x(x),y(y),z(z){}

};
//向量
typedef Point Vector;
//运算
Vector operator + (Vector A, Vector B){
    return Vector(A.x+B.x, A.y+B.y,A.z+B.z);
}
Vector operator - (Vector A, Vector B){
    return Vector(A.x-B.x, A.y-B.y,A.z-B.z);
}
Vector operator * (Vector A, double p){
    return Vector(A.x*p, A.y*p,A.z*p);
}
Vector operator / (Vector A, double p){
    return Vector(A.x/p, A.y/p,A.z/p);
}
bool operator == (Point A,Point B){
	return sgn(A.x-B.x)==0&&sgn(A.y-B.y)==0;
}
bool P_cmp1(Point a,Point b){
    if(a.x==b.x)
    	return a.y<b.y;
    return a.x<b.x;
}
//向量数量积  向量α在向量β的投影于向量β的长度乘积(带方向)
double Dot(Vector A, Vector B){
    return A.x*B.x + A.y*B.y + A.z*B.z;
}
//向量向量积  向量α与β所张成的平行四边形的有向面积
double Cross(Vector A, Vector B){
    return A.x*B.y-A.y*B.x;
}
//取模
double Length(Vector A){
    return sqrt(Dot(A, A));
}
//计算夹角
double Angle(Vector A, Vector B){
    return acos(Dot(A, B) / Length(A) / Length(B));
}
//向量旋转
Vector Rotate(Vector A, double rad){//rad为弧度 且为逆时针旋转的角
    return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad));
}
Vector Normal(Vector A){//向量A左转90°的单位法向量
    double L = Length(A);
    return Vector(-A.y/L, A.x/L);
}
//三角形外接圆圆心
Point Excenter(Point a, Point b, Point c){
    double a1 = b.x - a.x;
    double b1 = b.y - a.y;
    double c1 = (a1*a1 + b1*b1)/2;
    double a2 = c.x - a.x;
    double b2 = c.y - a.y;
    double c2 = (a2*a2 + b2*b2)/2;
    double d = a1*b2 - a2*b1;
    return Point(a.x + (c1*b2 - c2*b1)/d, a.y + (a1*c2 - a2*c1)/d);
}
//两点距离
double dis(Point a,Point b){
	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z));
}
/*------------------------------------------------------------------------------------------------*/
//线
struct Line{//直线定义
    Point v, p;
    //Line(Point v, Point p):v(v), p(p){}
    Point point(double t){//返回点P = v + (p - v)*t
        return v + (p - v)*t;
    }
};
//判断点是否在线上
bool PointOnline(Line A,Point a){
	Vector v1(A.p.x-a.x,A.p.y-a.y,A.p.z-a.z);
	Vector v2(A.v.x-a.x,A.v.y-a.y,A.v.z-a.z);
	return !(Cross(v1,v2));
}
//计算两直线交点 必须保证直线相交,否则将会出现除以零的情况
Point GetLineIntersection(Point a1, Point a2, Point b1, Point b2){
	Vector v = a1-a2;
	Vector w = b1-b2;
	Vector u = a1-b1;
    double t = Cross(w, u)/Cross(v, w);
    return a1+v*t;
}
//点P到直线AB距离公式
double DistanceToLine(Point P, Point A, Point B){
    Vector v1 = B-A, v2 = P-A;
    return fabs(Cross(v1, v2)/Length(v1));
}
//点P到线段AB距离公式
double DistanceToSegment(Point P, Point A, Point B){
    if(A.x == B.x&&A.y == B.y&&A.z == B.z)
        return Length(P-A);
    Vector v1 = B-A, v2 = P-A, v3 = P-B;
    if(dcmp(Dot(v1, v2),0) < 0)
        return Length(v2);
    if(dcmp(Dot(v1, v3),0) > 0)
        return Length(v3);
    return DistanceToLine(P, A, B);
}
//点P在直线AB上的投影点
Point GetLineProjection(Point P, Point A, Point B){
    Vector v = B-A;
    return A+v*(Dot(v, P-A)/Dot(v, v));
}
//判断点是否在线段端上
bool OnSegment(Point p, Point a1, Point a2){
    return dcmp(Cross(a1-p, a2-p),0) == 0 && dcmp(Dot(a1-p, a2-p),0) <= 0;
}
//判断线段相交
bool SegmentProperIntersection(Point a1, Point a2, Point b1, Point b2){
    double c1 = Cross(a2-a1, b1-a1), c2 = Cross(a2-a1, b2-a1);
    double c3 = Cross(b2-b1, a1-b1), c4 = Cross(b2-b1, a2-b1);
    //if判断控制是否允许线段在端点处相交,根据需要添加
    if(!sgn(c1) || !sgn(c2) || !sgn(c3) || !sgn(c4)){
        bool f1 = OnSegment(b1, a1, a2);
        bool f2 = OnSegment(b2, a1, a2);
        bool f3 = OnSegment(a1, b1, b2);
        bool f4 = OnSegment(a2, b1, b2);
        bool f = (f1|f2|f3|f4);
        return f;
    }
    return (sgn(c1)*sgn(c2) < 0 && sgn(c3)*sgn(c4) < 0);
}
//点c是否在线段ab的左侧 左1 线上0 右-1
int ToLeftTest(Point a, Point b, Point c){
    if( Cross(b - a, c - b) > 0) return 1;
    else if( Cross(b - a, c - b) == 0) return 0;
    else return -1;
}
/*------------------------------------------------------------------------*/
//多边形
//求凸包 多边形p  凸包ch
int ConvexHull(Point *p,int n,Point *ch){
	n=unique(p,p+n)-p;//去重
	sort(p,p+n,P_cmp1);
	int v=0;
	for(int i=0;i<n;i++){
		while(v>1&&Cross(ch[v-1]-ch[v-2],p[i]-ch[v-1])<=0)
			v--;
		ch[v++]=p[i];
	}
	int j=v;
	for(int i=n-2;i>=0;i--){
		while(v>j&&Cross(ch[v-1]-ch[v-2],p[i]-ch[v-1])<=0)
			v--;
		ch[v++]=p[i];
	}
	if(n>1) v--;
	return v;
}
//多边形有向面积
double PolygonArea(Point* p, int n){//p为端点集合,n为端点个数
    double s = 0;
    for(int i = 1; i < n-1; ++i)
        s += Cross(p[i]-p[0], p[i+1]-p[0]);
    return s;
}
//判断点是否在多边形内,若点在多边形内返回1,在多边形外部返回0,在多边形上返回-1
int isPointInPolygon(Point p, vector<Point> poly){
    int wn = 0;
    int n = poly.size();
    for(int i = 0; i < n; ++i){
        if(OnSegment(p, poly[i], poly[(i+1)%n])) return -1;
        int k = sgn(Cross(poly[(i+1)%n] - poly[i], p - poly[i]));
        int d1 = sgn(poly[i].y - p.y);
        int d2 = sgn(poly[(i+1)%n].y - p.y);
        if(k > 0 && d1 <= 0 && d2 > 0) wn++;
        if(k < 0 && d2 <= 0 && d1 > 0) wn--;
    }
    if(wn != 0)
        return 1;
    return 0;
}
/************************************************************************************/
bool cmp(Line a,Line b)
{
	return (a.p.x<b.p.x||(a.p.x==b.p.x&&a.v.x>b.v.x));
}
int main()
{
	Line Hou,PL;
	while(1)
	{
		Line x[1005];//在PL上不满足条件的区间
		double x1,x2,y;
		cin>>x1>>x2>>y;//输入HOUSE
		if(x1==0&&x2==0&&y==0)
			return 0;
		Hou.p.x=x1,Hou.p.y=y;
		Hou.v.x=x2,Hou.v.y=y;
		cin>>x1>>x2>>y;//输入PL
		PL.p.x=x1,PL.p.y=y;
		PL.v.x=x2,PL.v.y=y;
		int n,m=0;
		cin>>n;
		for(int i=0;i<n;i++)
		{
			Point l,r;//输入障碍的左右端点
			cin>>l.x>>r.x>>l.y;
			r.y=l.y;
			if(l.y<=PL.p.y||l.y>=Hou.p.y)//若障碍在hou上面或PL下面就没有影响
				continue;
			Point L,R;//在PL上看HOU不满足条件的左右端点
			L=GetLineIntersection(l,Hou.v,PL.v,PL.p);
			R=GetLineIntersection(r,Hou.p,PL.v,PL.p);
			//存入x
			if(L.x<PL.p.x)
				x[m].p=Point(x1,y);
			else if(L.x>PL.v.x)
				x[m].p=Point(x2,y);
			else
				x[m].p=Point(L.x,y);
			if(R.x>PL.v.x)
				x[m++].v=Point(x2,y);
			else if(R.x<PL.p.x)
				x[m++].v=Point(x1,y);
			else
				x[m++].v=Point(R.x,y);
		}
		if(m==0)
		{
			printf("%.2lf\n",x2-x1);
			continue;
		}
		sort(x,x+m,cmp);//排序按左端点升
//		for(int i=0;i<m;i++)
//			cout<<x[i].p.x<<' '<<x[i].v.x<<endl;
		vector<Line>asd;
		//合并x的重复区间
		for(int i=0;i<m;i++)
		{
			Line a=x[i];
			for(int j=i+1;j<m;j++)
			{
				if(x[j].p.x<=a.v.x)
				{
					a.v.x=max(x[j].v.x,a.v.x);
				}
				else
				{
					i=j-1;
					break;
				}
				if(j+1==m)
					i=m;
			}
			asd.push_back(a);
		}
		m=asd.size();
		double ans=asd[0].p.x-x1;
		for(int i=0;i+1<m;i++)
		{
			ans=max(asd[i+1].p.x-asd[i].v.x,ans);
		}
		ans=max(x2-asd[m-1].v.x,ans);
		if(ans==0)
			cout<<"No View\n";
		else
			printf("%.2lf\n",ans);
	}
}

2 6 6
0 15 0
3
1 2 1
3 4 1
12 13 1
8.80
1 5 5
0 10 0
1
0 15 1
No View
2 6 6
0 15 0
3
1 2 1
3 4 1
12 13 1
8.80
2 6 6
0 15 0
4
1 2 1
3 4 1
12 13 1
1 5 2
6.70
2 6 6
0 15 0
2
0 5 3
6 15 3
No View
2 6 6
0 15 0
2
6 10 1
0 2 1
4.00
2 6 6
0 15 0
1
2 6 7
15.00
2 6 6
0 15 0
1
2 6 7
15.00
2 6 6
0 15 0
1
4 4.5 5.5
No View
2 6 6
0 15 0
16
0 1 3
1.5 2 3
2.5 3 3
3.5 4 3
4.5 5 3
5.5 6 3
6.5 7 3
7.5 8 3
8.5 9 3
9.5 10 3
10.5 11 3
11.5 12 3
12.5 13 3
13.5 14 3
14.5 15 3
15.5 16 3
No View
2 6 6
0 15 0
16
0 1 .1
1.5 2 .1
2.5 3 .1
3.5 4 .1
4.5 5 .1
5.5 6 .1
6.5 7 .1
7.5 8 .1
8.5 9 .1
9.5 10 .1
10.5 11 .1
11.5 12 .1
12.5 13 .1
13.5 14 .1
14.5 15 .1
15.5 16 .1
0.44
2 6 6
0 15 0
14
0 1 3
1.5 2 3
2.5 3 3
3.5 4 3
4.5 5 3
5.5 6 3
8.5 9 3
9.5 10 3
10.5 11 3
11.5 12 3
12.5 13 3
13.5 14 3
14.5 15 3
15.5 16 3
1.00
2 6 6
0 4000000000 0
2
1 2 1
15 16 3
3999999970.00
2 6 6
0 15 1
5
1 1.5 6
17 18 1
3 5 3
0 20 10
0 20 0.5
8.00

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值