zoukankan      html  css  js  c++  java
  • [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.
    ");
            else
                printf("%.2lf
    ",Mx);
        }
    
    }
    


  • 相关阅读:
    一些网购体会
    图灵社区 : 阅读 : [讨论] Java语言被很多人抱怨语法繁琐、开发效率低、体系繁杂而笨重,为什么还有这么强的生命力,尤其是在企业软件领域?
    反爬虫策略浅析
    redis源码笔记 刘浩de技术博客 博客园
    欢迎阅读 Erlang OTP 设计原理文档!¶
    图灵社区 : 阅读 : 十年码农聚会报道——让高龄老码农social起来
    学了一年的c++,连个像样的程序都写不出来 C/C++ / C++ 语言
    2012年第一批中关村高端领军人才公示公告
    为什么Markdown+R有较大概率成为科技写作主流? ← 阳志平的个人网站::技术
    大道至易——"刺秦与灭秦"个人、团队的前途与未来
  • 原文地址:https://www.cnblogs.com/james1207/p/3283408.html
Copyright © 2011-2022 走看看