题意:
给出平面上的两条线段,现在有竖直下落的雨;
求这两条线段最多能接到多少雨;
题解:
听起来挺朴实的一道题,但是并不怎么好做,因为计算几何的实数。。
实际上可以把这道题分为两个步骤:判断水能不能进入容器,计算容器能装多少水;
第二步比较容易,我直接底乘高乱搞了;
主要是对接水的判断,这一步有一个挺正确的性质:
线段口的向量在较高边的向量和竖直向量中间的时候,接不到水;
然后直接上叉积判断一下就可以了;
具体可以照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;
}