BZOJ1185:[HNOI2007]最小矩形覆盖 凸包+旋转卡壳+三分
Mar 02, 2015 01:38:38 PM
思路:
首先有一个显然的性质:就是最小矩形必定有一条边与凸包的边重合.
然后我们自然就是对于每一条边考虑一下:首先找到距离这条边最远的点.然后从这个点到这条边做一条垂线段,用这条垂线段上下平移来得到两个边界.
于是我用旋转卡壳找最远的点,然后对于两边分别三分.
效率好像还不低.
#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef double f2;
static const f2 eps=1e-7;
inline int dcmp(const f2&x){return fabs(x)<eps?0:(x<0?-1:1);}
#define N 50010
struct Point{
f2 x,y;
Point(){}
Point(f2 _x,f2 _y):x(_x),y(_y){}
inline void read(){scanf("%lf%lf",&x,&y);}
inline void print(){printf("%.5lf %.5lf\n",x,y);}
bool operator<(const Point&B)const{return fabs(x-B.x)==0?y<B.y:x<B.x;}
Point operator+(const Point&B)const{return Point(x+B.x,y+B.y);}
Point operator-(const Point&B)const{return Point(B.x-x,B.y-y);}
Point operator*(const f2&p)const{return Point(x*p,y*p);}
};
Point getvec(const Point&v){return Point(-v.y,v.x);}
Point getmid(const Point&a,const Point&b){return Point((a.x+b.x)/2,(a.y+b.y)/2);}
f2 getdis(const Point&a,const Point&b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
f2 cross(const Point&a,const Point&b){return a.x*b.y-a.y*b.x;}
f2 area(const Point&a,const Point&b,const Point&c){return fabs(cross(a-b,a-c))*.5;}
struct Line{
Point p,v;
Line(Point p1,Point p2,bool d){p=p1,v=d?p1-p2:p2;}
};
Point getlineintersection(const Line&l1,const Line&l2){
return l1.p+l1.v*(cross(l1.p-l2.p,l2.v)/cross(l1.v,l2.v));
}
Point P[N],stk[N<<1];int top;
Point move(Point p,Point v,f2 l){
return p+v*(l/sqrt(v.x*v.x+v.y*v.y));
}
f2 res=1e10;
Point re[N];
int main(){
//freopen("tt.in","r",stdin);
int n;scanf("%d",&n);
register int i,j;
for(i=1;i<=n;++i)P[i].read();
sort(P+1,P+n+1);
int ins;for(ins=n;ins!=1&&dcmp(P[ins].x-P[ins-1].x)==0;--ins);
for(i=ins;i<=(n+ins)/2;++i)swap(P[i],P[n+ins-i]);
for(i=1;i<=n;++i){
if(!top)stk[++top]=P[i];
else{while(top>=2&&dcmp(cross(stk[top-1]-stk[top],stk[top]-P[i]))<=0)--top;stk[++top]=P[i];}
}
int instk=top;
for(i=ins-1;i>=1;--i){
if(top==instk)stk[++top]=P[i];
else{while(top>=instk+1&&dcmp(cross(stk[top-1]-stk[top],stk[top]-P[i]))<=0)--top;stk[++top]=P[i];}
}--top;
for(i=top+1;i<=2*top;++i)stk[i]=stk[i-top];
int r=2,L,R,ll,rr;
f2 h1,h2;
for(i=1;i<=top;++i){
while(area(stk[i],stk[i+1],stk[r])<=area(stk[i],stk[i+1],stk[r+1]))++r;
Line l1=Line(stk[i],stk[i+1],1);
Line l2=Line(stk[r],getvec(l1.v),0);
Point pr=getlineintersection(l1,l2);
h1=h2=0;
for(L=i+1,R=r;;){
if(R-L+1<=5){for(j=L;j<=R;++j)h1=max(h1,area(stk[r],pr,stk[j])*2/getdis(stk[r],pr));break;}
ll=L+(R-L+1)/3,rr=R-(R-L+1)/3;
if(area(stk[r],pr,stk[ll])<=area(stk[r],pr,stk[rr]))L=ll;else R=rr;
}
for(L=r,R=i+top;;){
if(R-L+1<=5){for(j=L;j<=R;++j)h2=max(h2,area(stk[r],pr,stk[j])*2/getdis(stk[r],pr));break;}
ll=L+(R-L+1)/3,rr=R-(R-L+1)/3;
if(area(stk[r],pr,stk[ll])<=area(stk[r],pr,stk[rr]))L=ll;else R=rr;
}
if(getdis(stk[r],pr)*(h1+h2)<res){
res=getdis(stk[r],pr)*(h1+h2);
re[0]=move(pr,stk[i]-stk[i+1],h1);
re[1]=move(stk[r],stk[i]-stk[i+1],h1);
re[2]=move(stk[r],stk[i+1]-stk[i],h2);
re[3]=move(pr,stk[i+1]-stk[i],h2);
}
}
printf("%.5lf\n",res);
int bins;Point Minre;
for(Minre=re[0],bins=0,i=1;i<4;++i)if(dcmp(re[i].y-Minre.y)<0||(dcmp(re[i].y-Minre.y)==0&&dcmp(re[i].x-Minre.x)<0))Minre=re[i],bins=i;
for(i=0;i<4;++i)re[(i+bins)%4].print();
return 0;
}
BZOJ1857:[Scoi2010]传送带 三分
Jan 15, 2015 10:19:05 AM
思路:
显然一条比较优的路径是从\(A\)走到\(AB\)上一点\(X\),然后从\(X\)走到\(CD\)上一点\(Y\),然后从\(Y\)走到\(D\).
关键是\(X,Y\)如何确定.
我们能够发现\(X\)点确定时,随着\(Y\)的移动,总路程是一个单峰函数.
更加神奇的是,随着\(X\)的移动,通过我们上述三分得到的总路程也是一个单峰函数!
没什么说的,三分套三分就行了.
#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef double f2;
#define eps 1e-8
struct Point{
f2 x,y;
void read(){scanf("%lf%lf",&x,&y);}
Point(){}
Point(f2 _x,f2 _y):x(_x),y(_y){}
Point operator-(const Point&B)const{return Point(B.x-x,B.y-y);}
Point operator+(const Point&B)const{return Point(x+B.x,y+B.y);}
Point operator*(const f2&p)const{return Point(p*x,p*y);}
}A,B,C,D;
int vab,vcd,vplane;
f2 sqr(const f2&x){return x*x;}
f2 Dist(const Point&A,const Point&B){return sqrt(sqr(A.x-B.x)+sqr(A.y-B.y));}
f2 f(Point x,Point l,Point v,f2 k){
return Dist(x,l+v*k)/vplane+Dist(l+v*k,l+v)/vcd;
}
f2 Solve(Point x,Point l,Point r){
Point v=l-r;
f2 L=0,R=1,LL,RR,ansl,ansr,lastans=1e12,nowans;
while(1){
LL=L+(R-L)/3,RR=R-(R-L)/3;
ansl=f(x,l,v,LL),ansr=f(x,l,v,RR);
if(ansl<ansr)R=RR,nowans=ansl;else L=LL,nowans=ansr;
if(fabs(nowans-lastans)<1e-5)break;lastans=nowans;
}
return lastans;
}
int main(){
A.read(),B.read(),C.read(),D.read();
scanf("%d%d%d",&vab,&vcd,&vplane);
f2 L=0,R=1,LL,RR,ansl,ansr,lastans=1e12,nowans;Point v=A-B;
while(1){
LL=L+(R-L)/3,RR=R-(R-L)/3;
ansl=Dist(A,A+v*LL)/vab+Solve(A+v*LL,C,D),ansr=Dist(A,A+v*RR)/vab+Solve(A+v*RR,C,D);
if(ansl<ansr)R=RR,nowans=ansl;else L=LL,nowans=ansr;
if(fabs(nowans-lastans)<1e-5)break;lastans=nowans;
}
printf("%.2lf",lastans);
return 0;
}