poj 3334 计算几何
有一个连通器,由两个漏斗组成,倒vol提及的水,问你连通器中水的高度是多少
解法:先求出水面可以到达的最低和最高的高度,然后二分答案判断
View Code
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const double eps = 1e-8; const int maxn = 1010; const double inf = 1000000000; int n,m; double vol,miny,maxy,ans; struct Point{ double x,y; Point(){}; Point(double x,double y){ this->x=x; this->y=y; } void read(){ scanf("%lf%lf",&x,&y); } }P[maxn],Q[maxn]; double min(double a,double b){ return a<b?a:b; } int sign(double x){ return (x>eps)-(x<-eps); } void input(){ int i; miny=inf; scanf("%lf",&vol); scanf("%d",&n); for(i=0;i<n;i++) { P[i].read(); if(sign(P[i].y-miny)<0) miny=P[i].y; } scanf("%d",&m); for(i=0;i<m;i++){ Q[i].read(); if(sign(Q[i].y-miny)<0) miny=Q[i].y; } maxy=min(min(P[0].y,P[n-1].y),min(Q[0].y,Q[m-1].y)); } double getarea(Point *p,int n){ int i; double area=0; for(i=0;i<n;i++) area+=p[(i+1)%n].y*(p[i].x-p[(i+2)%n].x); return fabs(area/2); } bool cross(Point a,Point b,double y){ return sign(a.y-y)*sign(b.y-y)<=0; } Point intersect(Point p1,Point p2,Point p3,Point p4){ Point p; double a1,b1,a2,b2,c1,c2,d; a1=p1.y-p2.y; b1=p2.x-p1.x; c1=p1.x*p2.y-p2.x*p1.y; a2=p3.y-p4.y; b2=p4.x-p3.x; c2=p3.x*p4.x-p4.x*p3.y; d=a1*b2-a2*b1; p.x=(-c1*b2+c2*b1)/d; p.y=(-a1*c2+a2*c1)/d; return p; } Point cut[maxn]; int tot; double getvol(double y,int n,Point P[]){ int i,j,k; tot=0; Point a=Point(0,y),b=Point(1,y); for(i=0;i<n-1;i++){ if(cross(P[i],P[i+1],y)){ cut[tot++]=intersect(P[i],P[i+1],a,b); break; } } for(j=i+1;j<n-1;j++){ cut[tot++]=P[j]; if(cross(P[j],P[j+1],y)){ cut[tot++]=intersect(P[j],P[j+1],a,b); break; } } double area=getarea(cut,tot); return area; } double gao(double y){ double a,b; a=getvol(y,n,P); b=getvol(y,m,Q); return a+b; } void solve(){ double l=miny,r=maxy,mid; while(fabs(l-r)>eps){ double mid=(l+r)/2; double test=gao(mid); int flag=sign(test-vol); if(flag<=0){ ans=mid; l=mid; } else r=mid; } } int main(){ int t,i,j; scanf("%d",&t); while(t--){ input(); solve(); printf("%.3lf\n",ans); } return 0; }