题意:
给出平面上的两条线段,现在有竖直下落的雨;
求这两条线段最多能接到多少雨;
题解:
听起来挺朴实的一道题,但是并不怎么好做,因为计算几何的实数。。
实际上可以把这道题分为两个步骤:判断水能不能进入容器,计算容器能装多少水;
第二步比较容易,我直接底乘高乱搞了;
主要是对接水的判断,这一步有一个挺正确的性质:
线段口的向量在较高边的向量和竖直向量中间的时候,接不到水;
然后直接上叉积判断一下就可以了;
具体可以照Discuss数据玩,那个还是很强的;
代码:
#include<math.h> #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const double EPS=1e-8; const double INF=1e10; struct Point { double x,y; Point(){} Point(double _,double __):x(_),y(__){} friend Point operator +(Point a,Point b) { return Point(a.x+b.x,a.y+b.y); } friend Point operator -(Point a,Point b) { return Point(a.x-b.x,a.y-b.y); } friend double operator ^(Point a,Point b) { return a.x*b.y-a.y*b.x; } friend double operator *(Point a,Point b) { return a.x*b.x+a.y*b.y; } friend Point operator *(double a,Point b) { return Point(a*b.x,a*b.y); } }; struct Line { Point p,v; Line(){} Line(Point _,Point __):p(_),v(__){} void read() { Point temp; scanf("%lf%lf%lf%lf",&p.x,&p.y,&temp.x,&temp.y); if(p.y>temp.y) swap(p,temp); v=temp-p; } Point operator [](int k) { if(k) return p+v; else return p; } friend bool Cross(Line a,Line b) { if((b.v^a[1]-b.p)*(b.v^a[0]-b.p)<EPS&&(a.v^b[1]-a.p)*(a.v^b[0]-a.p)<EPS&&fabs(a.v^b.v)>EPS) return 1; return 0; } friend Point getP(Line a,Line b) { Point u=a.p-b.p; double temp=(b.v^u)/(a.v^b.v); return a.p+temp*a.v; } }l1,l2; int main() { int n,m,i,j,k; double ans; scanf("%d",&n); for(i=1;i<=n;i++) { l1.read(),l2.read(); if(Cross(l1,l2)) { Point p=getP(l1,l2); if(l1[1].y<l2[1].y) { double height=l1[1].y-p.y; Point t1=l1[1]; Point t2=getP(Line(t1,Point(1,0)),l2); Point V=l2[1]-t1; if((V^Point(0,1))*(V^l2.v)<EPS) ans=0; else ans=fabs(t1.x-t2.x)*height/2; } else { double height=l2[1].y-p.y; Point t1=l2[1]; Point t2=getP(Line(t1,Point(1,0)),l1); Point V=l1[1]-t1; if((V^Point(0,1))*(V^l1.v)<EPS) ans=0; else ans=fabs(t1.x-t2.x)*height/2; } } else ans=0; printf("%.2lf\n",ans+EPS); } return 0; }