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

时间:2021-07-18 06:01:10

题意:

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

[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);
} }