poj 2826 An Easy Problem?! (變態卡資料題)
阿新 • • 發佈:2018-11-16
題目連結:poj 2826
題意:給出兩條直線,水從天上落下,問:這兩條直線組成的平面容器能裝多少水?
題解:很gou的題,超級變態卡資料,艹,足足搞了我幾天,總算搞出來了。
參考連結:https://www.cnblogs.com/kuangbin/p/3192511.html kuangbin神犇的,不過它程式碼少了一句話,已經加上去了
這種情況是覆蓋的,
注意答案要加eps,這是一個好習慣,浮點數運算可能得到-0.00,而測評機不接受負數,要加eps變為0.00。
習慣參考於:https://blog.csdn.net/wl16wzl/article/details/82107592
至於為什麼會這樣,目前還不是太清楚,以後再補充,反正我程式碼答案要不加eps的話,不能AC,kuangbin大佬的不加能AC,可以評測機也勢力......
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; typedef long long LL; struct point{ double x,y; point(){} point(double _x,double _y) { x=_x;y=_y; } }; struct LINE{ point a,b; LINE(){} LINE(point _a,point _b){ a=_a;b=_b; } }; point operator + (point A, point B) { return point(A.x + B.x, A.y + B.y); } point operator - (point A, point B) { return point(A.x - B.x, A.y - B.y); } point operator * (point A, double p) { return point(A.x * p, A.y * p); } point operator / (point A, double p) { return point(A.x/p, A.y/p); } bool operator < (const point& a, const point& b) { return a.x < b.x || (a.x == b.x && a.y < b.y); } const double eps = 1e-8; int dcmp(double x) { if(fabs(x) < eps) return 0; else return x < 0 ? -1 : 1; } bool operator == (const point& a, const point& b) { return dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0; } double Dot(point A, point B) { return A.x * B.x + A.y * B.y; } ///點積 double Cross(point A, point B) { return A.x * B.y - A.y * B.x; } ///叉積 point Getlinenode(point P, point v, point Q, point w) { ///兩直線交點(點,向量,點,向量) // printf("w.x=%f,w.y=%f\n",w.x,w.y); point u = P - Q; double t = Cross(w, u) / Cross(v, w); return P + v * t; } bool seg_seg_Cross(point s1,point e1,point s2,point e2)///判斷兩線段是否相交(不包括端點) { ///第一步,快速排斥實驗 if(!(min(s1.x,e1.x)<=max(s2.x,e2.x)&&min(s2.x,e2.x)<=max(s1.x,e1.x)&& min(s1.y,e1.y)<=max(s2.y,e2.y)&&min(s2.y,e2.y)<=max(s1.y,e1.y))) return false; double c1=Cross(s2-s1,e1-s1),c2=Cross(e1-s1,e2-s1); double c3=Cross(s1-s2,e2-s2),c4=Cross(e2-s2,e1-s2); if(dcmp(c1*c2)>=0&&dcmp(c3*c4)>=0) return 1; return 0; } bool line_seg_Cross(point s1,point e1,point s2,point e2) ///判斷直線與線段相交,s1e1表示直線,s2e2表示線段 { double c1=Cross(s2-s1,e1-s1),c2=Cross(e1-s1,e2-s1); ///==0表示,相交於端點也認定為相交 if(dcmp(c1*c2)>=0) return true; return false; } int main() { int ncase; double x1,y1,x2,y2,x3,y3,x4,y4; scanf("%d",&ncase); LINE l1,l2; while(ncase--) { scanf("%lf%lf%lf%lf%lf%lf%lf%lf",&x1,&y1,&x2,&y2,&x3,&y3,&x4,&y4); l1=LINE(point(x1,y1),point(x2,y2)); l2=LINE(point(x3,y3),point(x4,y4)); if(dcmp(y1-y2)==0||dcmp(y3-y4)==0){ ///某一個木板與地面平行 printf("0.00\n");continue; } if(dcmp(y1-y2)<0) swap(l1.a,l1.b); if(dcmp(y3-y4)<0) swap(l2.a,l2.b); if(seg_seg_Cross(l1.a,l1.b,l2.a,l2.b)==0){ ///兩木板沒有交點 printf("0.00\n");continue; } if(dcmp(Cross(l1.a-l1.b,l2.a-l2.b))==0){ ///兩木板平行或重合 printf("0.00\n");continue; } ///口被l2封掉 if(seg_seg_Cross(l1.a,point(l1.a.x,100000),l2.a,l2.b)){ printf("0.00\n");continue; } ///口被l1封掉 if(seg_seg_Cross(l2.a,point(l2.a.x,100000),l1.a,l1.b)){ printf("0.00\n");continue; } ///求面積了 point p=Getlinenode(l1.a,l1.a-l1.b,l2.a,l2.a-l2.b); ///求兩木板的交點 ///求過l1.a點並與地面平行的直線和直線l2的交點 point p1=Getlinenode(point(100000,l1.a.y),l1.a-point(100000,l1.a.y),l2.a,l2.b-l2.a); double ans1=fabs(Cross(p1-p,l1.a-p))/2.0; p1=Getlinenode(point(100000,l2.a.y),l2.a-point(100000,l2.a.y),l1.a,l1.b-l1.a); double ans2=fabs(Cross(p1-p,l2.a-p))/2.0; if(dcmp(ans1-ans2)<0) printf("%.2f\n",ans1+eps); ///這裡加個eps else printf("%.2f\n",ans2+eps); } return 0; } /* 10 0 5 3 0 1 1 3 0 3 0 6 3 3 0 5 1 3 0 6 3 3 0 7 3 0 1 1 0 1 0 2 1 0 1 2 1 1 0 1 2 0 5 3 0 2 5 3 0 */
再貼下神犇的程式碼:
#include <stdio.h> #include <math.h> #include <algorithm> #include <string.h> #include <math.h> using namespace std; const double eps = 1e-8; int sgn(double x) { if(fabs(x) < eps)return 0; if(x < 0)return -1; else return 1; } struct Point { double x,y; Point(){} Point(double _x,double _y) { x = _x;y = _y; } Point operator -(const Point &b)const { return Point(x - b.x,y - b.y); } //叉積 double operator ^(const Point &b)const { return x*b.y - y*b.x; } //點積 double operator *(const Point &b)const { return x*b.x + y*b.y; } }; struct Line { Point s,e; Line(){} Line(Point _s,Point _e) { s = _s;e = _e; } //兩直線相交求交點 //第一個值為0表示直線重合,為1表示平行,為0表示相交,為2是相交 //只有第一個值為2時,交點才有意義 pair<int,Point> operator &(const Line &b)const { Point res = s; if(sgn((s-e)^(b.s-b.e)) == 0) { if(sgn((s-b.e)^(b.s-b.e)) == 0) return make_pair(0,res);//重合 else return make_pair(1,res);//平行 } double t = ((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e)); res.x += (e.x-s.x)*t; res.y += (e.y-s.y)*t; return make_pair(2,res); } }; //*判斷線段相交 bool inter(Line l1,Line l2) { return max(l1.s.x,l1.e.x) >= min(l2.s.x,l2.e.x) && max(l2.s.x,l2.e.x) >= min(l1.s.x,l1.e.x) && max(l1.s.y,l1.e.y) >= min(l2.s.y,l2.e.y) && max(l2.s.y,l2.e.y) >= min(l1.s.y,l1.e.y) && sgn((l2.s-l1.e)^(l1.s-l1.e))*sgn((l2.e-l1.e)^(l1.s-l1.e)) <= 0 && sgn((l1.s-l2.e)^(l2.s-l2.e))*sgn((l1.e-l2.e)^(l2.s-l2.e)) <= 0; } int main() { int x1,y1,x2,y2,x3,y3,x4,y4; int T; Line l1,l2; scanf("%d",&T); while(T--) { scanf("%d%d%d%d%d%d%d%d",&x1,&y1,&x2,&y2,&x3,&y3,&x4,&y4); l1 = Line(Point(x1,y1),Point(x2,y2)); l2 = Line(Point(x3,y3),Point(x4,y4)); if(sgn(l1.s.y-l1.e.y)==0 || sgn(l2.s.y-l2.e.y) == 0) { printf("0.00\n"); continue; } if(sgn(l1.s.y-l1.e.y) < 0)swap(l1.s,l1.e); if(sgn(l2.s.y-l2.e.y) < 0)swap(l2.s,l2.e); if(inter(l1,l2) == false) { printf("0.00\n"); continue; } //口被封掉的情況 if(inter(Line(l1.s,Point(l1.s.x,100000)),l2) ) { printf("0.00\n"); continue; } //口被封掉 if(inter(Line(l2.s,Point(l2.s.x,100000)),l1) ) { printf("0.00\n"); continue; } pair<int,Point>pr; pr = l1 & l2; if(pr.first!=2) { ///原始碼少了這句話,判斷兩木板是否平行或重合 printf("0.00\n");continue; } Point p = pr.second; double ans1; pr = l1 & Line(Point(100000,l2.s.y),l2.s); Point p1 = pr.second; ans1 = fabs( (l2.s-p)^(p1-p) )/2; double ans2; pr = l2 & Line(Point(100000,l1.s.y),l1.s); Point p2 = pr.second; ans2 = fabs( (l1.s-p)^(p2-p) )/2; printf("%.2lf\n",min(ans1,ans2)); } return 0; }