hdu 3918 (Beiju)

来源:互联网 发布:调节色温的软件 编辑:程序博客网 时间:2024/05/16 19:16

题目大意:由两组从x轴向上延伸的相连线段(单调上升且互不相交)构成一个二维纸杯,其底为x轴,求其能装水的最大高度,这里不仅水不能溢出,而且还要考虑因重心与底的相对位置变化引起的翻到问题,即重心的x只能在底面的x左边范围之内、
解法:用一条与x轴平行的直线由底向上扫描,直到任意一段到达顶点或者重心x坐标超出,重心坐标超出的临界高度二分求出。

#include<cstdio>#include<cmath>#define eps 1e-8const 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;}


 

原创粉丝点击