计算几何题目:题目给出一些弯管,问最后从入口发射的光线能到达的最右端。
参考《算法艺术与信息学竞赛》p359,最优的发射光线只能是某个拐点上端点和某个拐点下端点的连线。
根据以上原理,我们从左往右判断光线是否能通过拐点连接的纵墙,若能通过所有则输出Through all the pipe.
若首先交于某墙壁,求出交点,保存最大值输出。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxN 22
struct point
{
float x,y;
};
point up[maxN];
point down[maxN];
float direction(point p1,point p2,point p3) //差积
{
return (p3.x-p1.x)*(p2.y-p1.y)-(p3.y-p1.y)*(p2.x-p1.x);
}
bool IsCrossBentWall(point upNode,point downNode,point wallUp, point wallDown) //检查光线是否能跨越横坐标为墙壁
{
float d1 = direction(upNode,downNode,wallUp);
float d2 = direction(upNode,downNode,wallDown);
if(d1*d2 <= 0) //墙壁端点在光线两端或者端点在光线上
return true;
else
return false;
}
float intersection(point p1,point p2,point p3,point p4) //两条直线交点
{
float k1 = (p2.y-p1.y)/(p2.x-p1.x);
float k2 = (p4.y-p3.y)/(p4.x-p3.x);
float dis = (p3.y-k2*p3.x-p1.y+k1*p1.x)/(k1-k2);
return dis;
}
float calcDis(int upNo,int downNo,int wallNo)
{
float x1 = -1e6;
float x2 = -1e6;
if(IsCrossBentWall(up[upNo],down[downNo],up[wallNo-1],up[wallNo])) //上壁
x1 = intersection(up[upNo],down[downNo],up[wallNo-1],up[wallNo]);
if(IsCrossBentWall(up[upNo],down[downNo],down[wallNo-1],down[wallNo])) //下壁
x2 = intersection(up[upNo],down[downNo],down[wallNo-1],down[wallNo]);
return x1>x2?x1:x2; //选出与上下壁想交点的较大x
}
int main()
{
int i,j,k;
int N;
char IsThroughAll;
float maxDis,tmpDis;
while(~scanf("%d",&N)&&N)
{
maxDis = -1e6;
for(i = 0;i < N;i++)
{
scanf("%f%f",&up[i].x,&up[i].y);
down[i].x = up[i].x;
down[i].y = up[i].y-1;
}
for(i = 0;i < N;i++)
{
for(j = 0;j < N;j++)
{
IsThroughAll = false;
if(i != j)
{
for(k = 0;k < N;k++)
{
if(k != i&&k != j&&!IsCrossBentWall(up[i],down[j],up[k],down[k]))
break;
}
if(k == N) //从前往后能通过最后一个纵墙
{
IsThroughAll = true;
break;
}
if(k > j) //最后通过的墙壁在光线下端点的右边
{
tmpDis = calcDis(i,j,k);
if(maxDis < tmpDis)
maxDis = tmpDis;
}
}
}
if(IsThroughAll)
break;
}
if(IsThroughAll)
{
printf("Through all the pipe.\n");
continue;
}
printf("%.2f\n",maxDis);
}
return 0;
}