nyoj 142 管道问题(线段相交问题)

来源:互联网 发布:微博系统源码 编辑:程序博客网 时间:2024/06/05 12:03
描述
有一宽度为1的折线管道,如图所示,上面的各个定点为 (x0,y0),(x1,y1),(x2,y2) ……(xn,yn),下面各个定点为(x0,y0-1),(x1,y1-1),(x2,y2-1)……(xn,yn-1),假设管道都是不透明的,不反射的,光线从左边入口的(x0,y0),(x0,y0-1)之间射入,向四面八方直线传播,问光线最远能射到哪里(x坐标)或能穿透整个管道。

                                        

输入
第一行有一个整数2<=n<20(n为零结束),表示有n个管道,接下来的n行表示n个管道的上面坐标(x0,y0),(x1,y1),(x2,y2)……(xn,yn)。测试数据组数大于0小于10000,所有坐标的只不大于10000。
输出
如果光线不能穿过管道,输出最远的x坐标,结果保留两位小数。如果有光线可以透过管道,输出“Through all the pipe.”
样例输入
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
样例输出
4.67

Through all the pipe

主要的思路就是穷举所有的折点的组合,取任意两个折点组成一条线,看看能不能跟所有的管道的上下折点构成的线段相交,如果所有都相交则说明光线能通过,否则求出所有光线中照的最远的那个(穷举的过程中设置一个记录变量) 这里就需要计算两个线段的交点(如果不能穿过管道,就要计算管道壁和光线的交点)。

#include<stdio.h>#include<iostream>#include<string.h>#include<math.h>#include<algorithm>#define E 1e-10using namespace std;struct zz{    double x;    double y;} p[25][2];double judge(zz a,zz b,zz c)//判断左右方向{    return ((b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y));}double check(zz a1,zz a2,zz b1,zz b2)//判断是否相交{    return judge(a1,a2,b1)*(judge(a1,a2,b2));}double zhexian(zz a,zz b,zz c)//计算三角形面积公式{    double s=((b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y))/2.0;    return fabs(s);}double point(zz a1,zz a2,zz b1,zz b2)//计算交点坐标{    double s1,s2;    s1=zhexian(a1,a2,b1);    s2=zhexian(a1,a2,b2);    return (s1*b2.x+s2*b1.x)/(s1+s2);}int main(){    int n;    while(scanf("%d",&n),n)    {        int i,j;        for(i=0; i<n; i++)        {            scanf("%lf%lf",&p[i][0].x,&p[i][0].y);            p[i][1].x=p[i][0].x;            p[i][1].y=p[i][0].y-1;        }        double mx=-0x3f3f3f3f;        bool flag=false;        zz a,b;        for(i=0; i<n&&flag==false; i++)        {            for(int tmp=0; tmp<2; tmp++)            {                a=p[i][tmp];                for(int x1=i+1; x1<n&&flag==false; x1++)                {                    for(int x2=0; x2<2&&flag==false; x2++)                    {                        b=p[x1][x2];                        if(check(a,b,p[0][0],p[0][1])<E)///相交说明光线是从管道口进入                        {                            for(j=1; j<n; j++)                            {                                if(check(a,b,p[j][0],p[j][1])>E)//如果a,b两点所连直线在p[j][1]、p[j][0],这个折点处没有交点,那么光线在这附近会有交点。                                {                                    double x;                                    if(judge(a,b,p[j][0])>0)                                        x=point(a,b,p[j-1][1],p[j][1]);                                    else                                        x=point(a,b,p[j-1][0],p[j][0]);                                    if(x>mx)                                        mx=x;                                    break;                                }                            }                            if(j==n)                                flag=true;                        }                    }                }            }        }        if(flag==true)            printf("Through all the pipe.\n");        else            printf("%.2lf\n",mx);    }    return 0;}


0 0
原创粉丝点击