链接:http://poj.org/problem?id=1039
题意:给一段曲折的管道,管道宽度为1,从管口射入光线,管子不透光、不反射,求光线最远能射到的地方的横坐标,如果光线能完全穿过管子,也输出。
思路:入射得最远的光线必然过管道的上下两个折点,由于数据量不大,所以可枚举两个折点得到一条直线。然后求直线与管道的交点。可以从左到右,通过比较在折点的横坐标处直线的纵坐标和对应折点纵坐标的大小来判断直线是与上下哪个管壁相交,然后求交点。最后取最大的横坐标值。
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; int n; const int maxn=22; int k; double ans,maxm; const double eps=1e-8; struct Point { double x,y; } up[maxn]; struct Line { double a,b,c; }; Line GetLine(Point p1,Point p2) { Line L; L.a=p2.y-p1.y; L.b=p1.x-p2.x; L.c=p2.x*p1.y-p1.x*p2.y; return L; } double inters(Line L1,Line L2) { double x=(L1.b*L2.c-L2.b*L1.c)/(L1.a*L2.b-L2.a*L1.b); return x; } void solve(Point p1,Point p2) { p2.y-=1; Line l=GetLine(p1,p2); double y; for(int i=0;i<n;i++) { y=-(l.a*up[i].x+l.c)/l.b; if(y-eps>up[i].y || y+eps<up[i].y-1) { k=0; if(i==0) break; if(y-eps>up[i].y)//上管壁 { Line l2=GetLine(up[i-1],up[i]); ans=inters(l,l2); } else//下管壁 { Point p3=up[i-1],p4=up[i]; p3.y-=1; p4.y-=1; Line l2=GetLine(p3,p4); ans=inters(l,l2); } break; } } } int main() { while(scanf("%d",&n) && n) { for(int i=0; i<n; i++) scanf("%lf%lf",&up[i].x,&up[i].y); ans=0.0; maxm=up[0].x;//横坐标值可为负,所以不能初始化为0.0 for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { k=0; if(i!=j) { k=1; solve(up[i],up[j]); maxm=max(ans,maxm); } if(k) break; } if(k) { cout<<"Through all the pipe.\n"; break; } } if(!k) printf("%.2f\n",maxm); } return 0; }
犯了两个错误,一是一开始虽然分了上下两个管壁来讨论,但是写的时候忘了写与下管壁相交的情况,还有就是看题不请,以为管道在x轴的正半轴,所以maxm的初始化为0,然后一直wa。。检查了好久才发现错误。。。
究竟是我抛弃了历史,还是历史遗弃了我。