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