[poj 1039]Pipes[线段相交求交点]

题意:

无反射不透明管子, 问从入口射入的所有光线最远能到达的横坐标. 贯穿也可.

[poj 1039]Pipes[线段相交求交点]

思路:

枚举每一组经过 up [ i ] 和 down [ j ] 的直线, 计算最远点.

因为无法按照光线生成的方式确定点斜式的起始点及斜率(连续的), 于是换另一种思路:

反正最终是要判断可行的直线, 就直接选择一些有代表性的直线, 覆盖所有边界即可.

于是考虑边界是什么.

首先可以发现: 由于光线是入口整个发出的, 其实也就是入口和拐点是平等的. 只要判相交.

只要覆盖在整个管道范围内的直线就可以, 由于不知道管道的形状特点, 只能暴力枚举每一组上下界. 能够完全穿过的直线就取"恰好与出口的一端相交"的情况.

这样做就将当前所枚举的两端点视为一段管道, 当前直线可以穿过当前等效管道, 判别是否可以穿过其他管道(包括等效管道内部的真实管道). 

也就是将一系列判别满足的问题拆分为, 保证单个问题满足, 并用此一单个问题 粗略划定的范围去测试其它. 这样就解决了用来测试的范围无从确定的障碍.


难点就在于想到如何遍历所有可行的直线.

 

//Memory  Time

//456K    63MS



#include<iostream>

#include<cmath>

#include<iomanip>

using namespace std;



const double precision=1e-3;   //精度限制

const double inf=99999.0;   //正无穷,注意下面使用的是负无穷



typedef class Node    //折点坐标

{

public:

	double x;

	double y;

}point;



int max(int a,int b)

{

	return a>b?a:b;

}



/*把浮点p的值转化为0,1或-1  (精度讨论)*/



int dblcmp(double p)

{

	if(fabs(p)<precision)    // fabs()  浮点数的绝对值

		return 0;       //只要是在0的邻域,就认为是0



	return p>0?1:-1;

}



/*叉积运算*/



double det(double x1,double y1,double x2,double y2)

{

	return x1*y2-x2*y1;

}



/*计算P点在AB的顺侧还是逆侧*/



double cross(point A,point B,point P)//AB x AP

{

	return det(B.x-A.x , B.y-A.y , P.x-A.x , P.y-A.y);

}



/*判断直线AB与线段CD是否相交*/



bool check(point A,point B,point C,point D)

{

	return (dblcmp(cross(A,B,C)) * dblcmp(cross(A,B,D)) <= 0);//在异侧或在线上

}



/*计算直线AB和线段CD的交点横坐标*/



double intersection(point A,point B,point C,point D)

{

	double area1=cross(A,B,C);

	double area2=cross(A,B,D);

	int c=dblcmp(area1);

	int d=dblcmp(area2);



	if(c*d<0) //C,D在直线AB的两侧,规范相交

		return (area2*C.x - area1*D.x)/(area2-area1);  //交点计算公式



	if(c*d==0){   //CD的其中一个端点在AB上,不规范相交

		if(c==0)

			return C.x;

		else

			return D.x;

	}

	return -inf;  //CD在AB同侧,无交点,返回 负无穷

}



int main()

{

	int n,i,j,k;    //折点数

	while(cin>>n)

	{

		if(!n)

			break;



		point* up=new point[n+1];         //上折点

		point* down=new point[n+1];       //下折点



		double max_x=-inf;  //最大可见度(管中最远可见点的横坐标)

		/*Input*/



		for(i=1;i<=n;i++)

		{

			cin>>up[i].x>>up[i].y;

			down[i].x=up[i].x;

			down[i].y=up[i].y-1;

		}



		bool flag=false;  //标记当前光线L(直线up[i]->down[j])能否贯通全管

		for(i=1;i<=n;i++) //枚举所有通过一个上折点、一个下折点的直线

		{

			for(j=n;j>=1;j--)

				if(i!=j)

				{

					for(k=1;k<=n;k++)     //直线L最大延伸到第k-1节管子

						if(!check(up[i],down[j],up[k],down[k]))   //up[k]->down[k]为折点处垂直x轴的直线

							break;



					if(k>n)//顺利结束循环,可以贯穿

					{

						flag=true;

						break;

					}

					else if(k>max(i,j))  //判断与第k-1节管子的上管壁还是下管壁相交

					{

						double temp=intersection(up[i],down[j],up[k],up[k-1]);

						if(max_x < temp)

							max_x=temp;



						temp=intersection(up[i],down[j],down[k],down[k-1]);

						if(max_x < temp)

							max_x=temp;

					}

				}



			if(flag)

				break;

		}



		if(flag)

			cout<<"Through all the pipe."<<endl;

		else

			cout<<fixed<<setprecision(2)<<max_x<<endl;



		/*Relax Room*/



		delete up;

		delete down;

	}

	return 0;

}

自己敲一遍:

 

 

#include <cstdio>

#include <cmath>

using namespace std;

const double EPS = 1e-6;///写成int了= =

const int INF = 0x3f3f3f3f;

const int MAXN = 25;

typedef struct node

{

    double x,y;

}point;

point up[MAXN],down[MAXN];



int max(int a, int b)

{

    int diff = b - a;

    return b - (diff & (diff>>31));

}



int dcmp(double p)

{

    if(fabs(p)<EPS)

        return 0;

    return p>0?1:-1;

}



double det(double x1, double y1, double x2, double y2)

{

    return x1*y2 - x2*y1;

}



double cross(point A, point B, point P)

{



    return det(B.x - A.x, B.y - A.y, P.x - A.x, P.y - A.y);;

}



bool check(point A, point B, point C, point D)

{

    return (dcmp(cross(A, B, C)) * dcmp(cross(A, B, D)) <= 0);//规范或不规范相交

}



double intersection(point A, point B, point C, point D)

{

    double area1 = cross(A, B, C);

    double area2 = cross(A, B, D);

    int c = dcmp(area1);

    int d = dcmp(area2);

    if(c*d<0)

    {

        return (area2 * C.x - area1 * D.x)/(area2 - area1);

    }

    if(!(c*d))

    {

        if(!c)

            return C.x;

        else

            return D.x;

    }

    return -INF;

}



int main()

{

    int n;

    while(scanf("%d",&n)==1 && n)

    {

        double Mx = -INF;

        for(int i=1;i<=n;i++)

        {

            scanf("%lf %lf",&up[i].x,&up[i].y);

            down[i].x = up[i].x,down[i].y = up[i].y - 1;

        }

        bool flag = false;

        for(int i=1;i<=n;i++)

        {

            for(int j=1,k;j<=n;j++)

            {

                if(i==j)

                    continue;

                for(k=1;k<=n;k++)

                {

                    if(!check(up[i],down[j],up[k],down[k]))

                        break;

                }



                if(k>n)

                {

                    flag = true;

                    break;

                }

                if(k>max(i,j))

                {

                    double temp = intersection(up[i],down[j],up[k],up[k-1]);

                    if(Mx < temp)

                        Mx = temp;

                    temp = intersection(up[i],down[j],down[k],down[k-1]);

                    if(Mx < temp)

                        Mx = temp;

                }

            }

            if(flag)

                break;

        }

        if(flag)

            printf("Through all the pipe.\n");

        else

            printf("%.2lf\n",Mx);

    }



}


 

 

你可能感兴趣的:(poj)