poj 2826 题解
题意:给出两条线段的位置(可相交),用它们来接落下来的雨水,问最终储水量是多少
题解:基本思路是求出两条线段交点,然后计算在交点上方部分三角形(短板效应,大小由较小的y确定)的面积即可。
注意点:事实上这个问题是判定+计算,要判定能不能接到水,再进行计算。
判定①:线段不相交或平行,则接不到水
判定②:以交点为起点的两条向上的两条线段中,一条线段完全挡住了另一条线段,则接不到水
由于存在判定,所以会出现精度问题,要注意eps的使用
实现:
①每条线段被交点分成两部分,用(1,0)×线段,选取结果大于零的那条,即是在上方的
②判断完全挡住的时候,先比较x值(是否同号,以及大小),再用x*det的正负号进行判断(在一,四象限,覆盖时两条线段方向有区别)
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const double eps=1e-9; struct point{ double x,y; point(){} point (double a,double b): x(a),y(b) {} friend point operator + (const point &a,const point &b){ return point(a.x+b.x,a.y+b.y); } friend point operator - (const point &a,const point &b){ return point(a.x-b.x,a.y-b.y); } friend point operator * (const double &r,const point &a){ return point(r*a.x,r*a.y); } friend point operator / (const point &a,const double &r){ return point(a.x/r,a.y/r); } double norm(){ return sqrt(x*x+y*y); } }; inline double det(point a,point b) {return a.x*b.y-a.y*b.x;} inline bool line_cross_segment(point s,point t,point a,point b) { return !(det(s-a,t-a)*det(s-b,t-b)>eps); } inline bool parallel(point a,point b,point c,point d){return abs(det(a-b,c-d))<eps;} inline bool seg_cross_seg(point a,point b,point c,point d) { if (min(c.x,d.x)>max(a.x,b.x)+eps || min(a.x,b.x)>max(c.x,d.x)+eps || min(c.y,d.y)>max(a.y,b.y)+eps || min(a.y,b.y)>max(c.y,d.y)+eps) return false; return det(a-c,d-c)*det(b-c,d-c)<eps && det(c-a,b-a)*det(d-a,b-a)<eps; } inline point line_make_point(point s1,point t1,point s2,point t2) //逻辑上必须先判断parallel { double a1=det(s1-s2,t2-s2); double a2=det(t1-s2,t2-s2); return (a1*t1-a2*s1)/(a1-a2); } int n; point s1,t1,s2,t2,cr,hx,h1,h2; double l1,l2; double ans; inline bool check(point l1,point l2) { if (l1.x*l2.x<eps) return true; if (abs(l1.x)>abs(l2.x)-eps && l1.x*det(l1,l2)<eps) return false; if (abs(l2.x)>abs(l1.x)-eps && l2.x*det(l2,l1)<eps) return false; return true; } int main() { scanf("%d",&n); while (n--) { scanf("%lf%lf%lf%lf",&s1.x,&s1.y,&t1.x,&t1.y); scanf("%lf%lf%lf%lf",&s2.x,&s2.y,&t2.x,&t2.y); if (parallel(s1,t1,s2,t2) || !(seg_cross_seg(s1,t1,s2,t2))) { printf("0.00\n"); continue; } cr=line_make_point(s1,t1,s2,t2); hx=point(1,0); if (det(hx,s1-cr)>eps) h1=s1-cr;else h1=t1-cr; if (det(hx,s2-cr)>eps) h2=s2-cr;else h2=t2-cr; l1=h1.y;l2=h2.y; if (l1<eps || l2<eps || !check(h1,h2)) { printf("0.00\n"); continue; } if (l1>=l2) h1=l2*h1/l1; else h2=l1*h2/l2; printf("%.2f\n",abs(det(h1,h2)/2)); } return 0; }