题目大意:由两组从x轴向上延伸的相连线段(单调上升且互不相交)构成一个二维纸杯,其底为x轴,求其能装水的最大高度,这里不仅水不能溢出,而且还要考虑因重心与底的相对位置变化引起的翻到问题,即重心的x只能在底面的x左边范围之内、
解法:用一条与x轴平行的直线由底向上扫描,直到任意一段到达顶点或者重心x坐标超出,重心坐标超出的临界高度二分求出。
#include<cstdio>
#include<cmath>
#define eps 1e-8
const int maxn=105;
struct point{
double x,y;
point(double xx=0,double yy=0){ x=xx;y=yy;}
}left[maxn],right[maxn],list[5];
int dcmp(double k){
return (k>eps)-(k<-eps);
}
double cross(point a,point b,point c){
return (c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y);
}
double area(point* p,int k){//多边形面积
double s1=0,s2=0;
for(int i=0;i<k;i++)
s1+=p[(i+1)%k].y*p[i].x,s2+=p[(i+1)%k].y*p[(i+2)%k].x;
return fabs(s1-s2)/2;
}
point intersection(point u1,point u2,point v1,point v2){//直线交点
point ret=u1;
double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x))
/((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));
ret.x+=(u2.x-u1.x)*t;
ret.y+=(u2.y-u1.y)*t;
return ret;
}
point gravity(point *p, int k){
double area = 0;
point center;
center.x = 0;
center.y = 0;
for (int i = 0; i < k-1; i++){
area += (p[i].x*p[i+1].y - p[i+1].x*p[i].y)/2;
center.x += (p[i].x*p[i+1].y - p[i+1].x*p[i].y) * (p[i].x + p[i+1].x);
center.y += (p[i].x*p[i+1].y - p[i+1].x*p[i].y) * (p[i].y + p[i+1].y);
}
area += (p[k-1].x*p[0].y - p[0].x*p[k-1].y)/2;
center.x += (p[k-1].x * p[0].y - p[0].x * p[k-1].y) * (p[k-1].x + p[0].x);
center.y += (p[k-1].x * p[0].y - p[0].x * p[k-1].y) * (p[k-1].y + p[0].y);
center.x /= 6*area;
center.y /= 6*area;
return center;
}
int n,m;
point l_pre,r_pre,l_now,r_now;
double x_pre,area_pre,x_now,area_now,xx;
void init_now(){
list[0]=l_pre;list[1]=r_pre;list[2]=r_now;list[3]=l_now;
area_now=area(list,4);
x_now=gravity(list,4).x;
xx=(x_pre*area_pre+x_now*area_now)/(area_pre+area_now);
}
bool ok(double xx){
return dcmp(xx-left[0].x)>=0&&dcmp(xx-right[0].x)<=0;
}
bool fun(double h){
point p1=point(l_pre.x,l_pre.y+h);
point p2=point(r_pre.x,r_pre.y+h);
l_now=intersection(l_pre,l_now,p1,p2);
r_now=intersection(r_pre,r_now,p1,p2);
init_now();
return ok(xx);
}
int ll,rr;
void solve(){
ll=rr=0;
area_pre=0;
l_pre=left[0];r_pre=right[0];
while(ll<n-1&&rr<m-1){
int tl=ll+1,tr=rr+1;
if(left[tl].y==right[tr].y){
ll=tl;rr=tr;
l_now=left[tl];r_now=right[tr];
}else if(left[tl].y>right[tr].y){//左边高,取右边
rr=tr;
r_now=right[rr];
l_now=intersection(left[ll],left[tl],r_now,point(r_now.x+1.0,r_now.y));
}else{//右边高,取左边
ll=tl;
l_now=left[ll];
r_now=intersection(right[rr],right[tr],l_now,point(l_now.x+1.0,l_now.y));
}
init_now();
if(ok(xx)){
l_pre=l_now;r_pre=r_now;
x_pre=xx;area_pre+=area_now;
}else{
double low=0,high=l_now.y-l_pre.y,mid;
while(low+1e-6<high){
mid=(low+high)/2;
if(fun(mid)) low=mid;
else high=mid;
}
printf("%.3lf\n",l_pre.y+low);
return;
}
}
printf("%.3lf\n",l_pre.y);
}
int main(){
int ca;
scanf("%d",&ca);
while(ca--){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++) scanf("%lf%lf",&left[i].x,&left[i].y);
for(int i=0;i<m;i++) scanf("%lf%lf",&right[i].x,&right[i].y);
solve();
}
return 0;
}