http://poj.org/problem?id=1039
计算几何就是麻烦 这精度那精度的。。
题意:有一打折的管道,从管口射入光线,求光线能传播的最长x距离。
最长肯定是 一上一下的连接 枚举所有这样的连线 再判断是能穿过这个折点。能穿过:折点上下两个点在线段两侧。若不能算一下相交点在哪里,求出坐标,与maxx相比取较大值。
刚才CF去了 回来补完。。
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stdlib.h>
#include<cmath>
using namespace std;
#define eps 1e-8
typedef struct node
{
double x,y;
}point;
point up[110],down[110];
double cross(point a,point b,point c)//差乘判左右 a->b与a->c向量的关系
{
return (a.x-c.x)*(a.y-b.y)-(a.y-c.y)*(a.x-b.x);
}
int sig(double x)
{
if(fabs(x)<eps)
return 0;
return (x>0)?1:-1;
}
double intersection1(point a,point b,point c,point d)//直线交点求解
{
point pp = a;
double t = ((a.x-c.x)*(c.y-d.y)-(a.y-c.y)*(c.x-d.x))/
((a.x-b.x)*(c.y-d.y)-(a.y-b.y)*(c.x-d.x));
pp.x+=(b.x-a.x)*t;
pp.y+=(b.y-a.y)*t;
return pp.x;
}
int intersection(point a,point b,point c,point d)//两线段是否相交 一线段的两端点在另一线段的两侧
{
double d1 = cross(a,b,c);
double d2 = cross(a,b,d);
if(d1*d2>=0)
return 0;
return 1;
}
int main()
{
int i,j,k,n;
while(cin>>n)
{
if(n==0)
break;
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;
}
double maxx = up[1].x;
int flag = 0;
for(i = 1; i <= n ; i++)
{
for(j = 1 ; j <= n ; j++)
{
if(i==j)
continue;
for(k = 1; k <= n ; k++)
{
double d1 = sig(cross(up[i],down[j],up[k]));
double d2 = sig(cross(up[i],down[j],down[k]));
if(k==1&&d1*d2<=0)//因为下面有k-1的运算 所以先特判一下第一个折点 也就是入口点
continue;
if(k==1&&d1*d2>0)
break;
if(d1*d2>0)
{
if(intersection(up[i],down[j],up[k],up[k-1]))//交点在上管壁 这里排除了交点在折点端点处 这种情况会累积到下一个K值进行计算 下面会有计算
{
double tx = intersection1(up[i],down[j],up[k],up[k-1]);
maxx = max(maxx,tx);
break;
}
if(intersection(up[i],down[j],down[k],down[k-1]))//交点在下管壁
{
double tx = intersection1(up[i],down[j],down[k],down[k-1]);
maxx = max(maxx,tx);
break;
}
maxx = max(maxx,up[k-1].x);//如果都没有相交 也就是交在上一个K值的端点处
break;
}
}
if(k==n+1)
{
flag = 1;
break;
}
}
if(flag)
break;
}
if(flag)
printf("Through all the pipe.\n");
else
printf("%.2lf\n",maxx);
}
return 0;
}