题目大意:有一个不反光并且不透光的管道,现在有一束光线从最左端进入,问能达到的最右端是多少,输出x坐标。
分析:刚开始做是直接枚举两个点然后和管道进行相交查询,不过这样做需要考虑的太多,细节不容易掌控。后来发现其实只需要对接口进行一下相交查询就简单多了,因为只需要考虑能不能通过每个截口就可以了,而且这样做的好处还有没有平行线和重叠线的情况,因为所有的截口都是垂直于x轴的,换一种想法海阔太空啊。
代码如下:
==========================================================================================================================
#include<stdio.h> #include<math.h> #include<algorithm> using namespace std; const int MAXN = 107; const double EPS = 1e-8; const double oo = 1e9+7; int Sign(double t) { if(t > EPS)return 1; if(fabs(t)<EPS)return 0; return -1; } struct Point { double x, y; Point(double x=0, double y=0):x(x), y(y){} Point operator - (const Point &t)const{ return Point(x-t.x, y-t.y); } double operator ^(const Point &t)const{ return x*t.y - y*t.x; } bool operator == (const Point &t)const{ return fabs(x-t.x)<EPS && fabs(y-t.y)<EPS; } }; struct Segment { Point S, E; double a, b, c;///ax + by = c; Segment(Point S=0, Point E=0):S(S),E(E){ ///求线段所在的直线的常数项 a = S.y - E.y; b = E.x - S.x; c = E.x*S.y - S.x*E.y; } bool Inters(const Segment &tmp) const{ int t1 = Sign((S-E)^(tmp.S-E)); int t2 = Sign((S-E)^(tmp.E-E)); ///不存在平行,或者共线情况,有一点相交都算相交 if(t1+t2==2 || t1+t2==-2) return false; else return true; } Point crossNode(const Segment &tmp)const{ ///求交点 Point t; t.x = (c*tmp.b-tmp.c*b) / (a*tmp.b-tmp.a*b); t.y = (c*tmp.a-tmp.c*a) / (b*tmp.a-tmp.b*a); return t; } void MakeNewSeg(double Lx, double Rx) {///构造新的线段,与原来的线段共线 S.x = Lx, S.y = (c-a*Lx) / b; E.x = Rx, E.y = (c-a*Rx) / b; } }; double FindMinX(Segment s, Segment sg[], int N) { double ans=oo; for(int i=1; i<N; i++) { if(s.Inters(sg[i])) continue; Segment t1(sg[i-1].S, sg[i].S); Segment t2(sg[i-1].E, sg[i].E); if(s.Inters(t1)) { Point tmp = s.crossNode(t1); ans = tmp.x; } if(s.Inters(t2)) { Point tmp = s.crossNode(t2); if(fabs(ans-oo) < EPS) ans = tmp.x; else ans = max(ans, tmp.x); } break; } return ans; } int main() { int N; while(scanf("%d", &N) != EOF && N) { Point p[MAXN]; Segment sg[MAXN]; int k=0; for(int i=0; i<N; i++, k+=2) { scanf("%lf%lf", &p[k].x, &p[k].y); p[k+1].x = p[k].x, p[k+1].y = p[k].y - 1.0; sg[i] = Segment(p[k], p[k+1]); } double ans = -oo; for(int i=0; i<k; i++) for(int j=i+1; j<k; j++) { if(fabs(p[i].x-p[j].x) < EPS) continue; Segment s(p[i], p[j]); s.MakeNewSeg(sg[0].S.x, sg[N-1].S.x); if(s.Inters(sg[0])) ans = max(ans, FindMinX(s, sg, N)); /// printf("i=%d, j=%d, ans=%f ", i, j, ans); } if(fabs(ans-oo) < EPS) printf("Through all the pipe. "); else printf("%.2f ", ans); } return 0; }