POJ-1039-Pipe-枚举(计算几何)

http://poj.org/problem?id=1039


题意:给一根折线管道,有光源从入口发射,问光源最远到达的地方。


首先最优的方案肯定是 选择第i部分的上点和第j部分的下点,或上下相反


那么直接枚举所有的这样的点对,然后判断这对 点  能否

 【与从1到j-1之间的所有竖线相交(竖线:第i部分的上下两点连成的直线)】


满足这个条件后,说明光线可以从入口射入,然后我们遍历j+1之后的部分,如果这对点i,j形成的直线能与 第k条竖线相交,表示能通过该管。。。直到找到一条不相交的竖线,然后求交点,更新答案


#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std; 
const double pi=acos(-1.0);
double eps=1e-5;  
struct POINT
{
	double x;
	double y;
	POINT(double a=0, double b=0) { x=a; y=b;}
	bool operator ==(POINT bb)
	{
		if (fabs(x-bb.x)<eps && fabs(y- bb.y)<eps)
			return true;
		else return false;
	}
}; 
POINT tm[25]; 
struct LINESEG
{
	POINT s;
	POINT e;
	LINESEG(POINT a, POINT b) { s=a; e=b;}
	LINESEG() { }
};
LINESEG  line[30]; 
double multiply(POINT sp,POINT ep,POINT op)
{
	return((sp.x-op.x)*(ep.y-op.y) - (ep.x-op.x)*(sp.y-op.y));
}
/* 判断点p是否在线段l上
条件:(p在线段l所在的直线上)&& (点p在以线段l为对角线的矩形内) */
bool online(LINESEG l,POINT p)
{
	return (fabs(multiply(l.e,p,l.s))<eps
		&& ( ( (p.x-l.s.x) * (p.x-l.e.x) <=0 ) && ( (p.y-l.s.y)*(p.y-l.e.y) <=0 ) ) );
}
 
struct LINE
{
	double a; 
	double b;
	double c;
	LINE(double d1=1, double d2=-1, double d3=0) {a=d1; b=d2; c=d3;}
};
LINE makeline(POINT p1,POINT p2)
{
	LINE tl;
	int sign = 1;
	tl.a=p2.y-p1.y;
	if(tl.a<0)
	{
		sign = -1;
		tl.a=sign*tl.a;
	}
	tl.b=sign*(p1.x-p2.x);
	tl.c=sign*(p1.y*p2.x-p1.x*p2.y);
	return tl;
}
// 如果两条直线 l1(a1*x+b1*y+c1 = 0), l2(a2*x+b2*y+c2 = 0)相交,返回true,且返回交点p
bool lineintersect(LINE l1,LINE l2,POINT &p) // 是 L1,L2
{
	double d=l1.a*l2.b-l2.a*l1.b;
	if(abs(d)<eps) // 不相交
		return false;
	p.x = (l2.c*l1.b-l1.c*l2.b)/d;
	p.y = (l2.a*l1.c-l1.a*l2.c)/d;
	return true;
}
bool intersect_l(LINESEG u,LINESEG v)
{
return multiply(u.s,v.e,v.s)*multiply(v.e,u.e,v.s)>=0;
}
 
int main()
{
	int i,j,k;  
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		if (!n)break;
		for (i=1;i<=n;i++)
		{
			scanf("%lf%lf",&tm[i].x,&tm[i].y);
		}
		for (i=1;i<=n;i++)	//构造竖线
		{
			line[i].s=tm[i];
			line[i].e=POINT(tm[i].x,tm[i].y-1);
		}
		double maxx=-2147483647;
		int who=-2;
		
		POINT p;
		for (i=1;i<=n;i++)		//枚举所有点
		{
			for (j=i+1;j<=n;j++)
			{ 
				for (int gg=1;gg<=2;gg++)//i上j下和i下j上两种姿势
				{ 
					LINESEG tmp;
					 if (gg==1)
					{tmp.s=tm[i],tmp.e=POINT(tm[j].x,tm[j].y-1);}
					if (gg==2)
					{tmp.s=POINT(tm[i].x,tm[i].y-1),tmp.e=tm[j];}
					 
					
					int flag=0;
					LINE ll1,ll2;
					ll1=makeline(tmp.s,tmp.e);
					for (k=1;k<=j-1;k++)	//保证能从入口进来
					{
							if (!intersect_l(line[k],tmp))	//求线段tmp所在直线是否与线段line相交
						{
							flag=1;
							break;
						}
					}
					if (flag)continue;		//光线不能从入口射入
					flag=-1;
					for (k=j+1;k<=n;k++)
					{
						if (!intersect_l(line[k],tmp))	//不能通过该管
						{
							double temp=-2147483647;
							flag=k;
							LINE up=makeline(tm[k-1],tm[k]);
							LINESEG upup(tm[k-1],tm[k]);
							lineintersect(ll1,up,p);
							if (online(upup,p))			//求交点并更新
								temp=p.x;	
							  
								LINE down=makeline(POINT(tm[k-1].x,tm[k-1].y-1),POINT(tm[k].x,tm[k].y-1));
									LINESEG dndn(POINT(tm[k-1].x,tm[k-1].y-1),POINT(tm[k].x,tm[k].y-1));
								lineintersect(ll1,down,p);
								if (online(dndn,p))  
								{
									if (p.x>temp)
									temp=p.x; 
								}
								p.x=temp;
								break; 
						}
					}
					if (flag==-1)
						p.x=tm[n].x;
					
					if (p.x>maxx)
					{
						maxx=p.x;
						who=flag;
					}
				}
			}
		}
			if (who==-1)
				printf("Through all the pipe.\n"); 
			else
				printf("%.2f\n",maxx);
			
			
		} 
		return 0;
		
	}


你可能感兴趣的:(POJ-1039-Pipe-枚举(计算几何))