题目大意:给定一条折线,要求选择一个点建立高度为h的瞭望塔,要求瞭望塔塔顶可以看到折线上的每一个点,求h的最小值
正解:半平面交
不会!
于是我们选择模拟退火来寻找瞭望塔的横坐标
确定瞭望塔的高度的时候我们选择二分处理 对于二分的每一个值 我们把折线上的端点从左到右枚举 瞭望塔的塔尖到每个端点的连线必须从左到右逆时针顺序 否则就会被遮挡
如图,塔尖到点2的连线在到点1的连线的顺时针方向,故点1被遮挡,该高度不可行
写完交上去各种秒WA,最后发现我的INF又不够大。。。我沙茶,我蒟蒻,我这个不长记性的大二货0.0
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 310 using namespace std; struct point{ double x,y; point(){} point(double X,double Y) { x=X; y=Y; } }points[M]; point operator - (const point &x,const point &y) { return point(x.x-y.x,x.y-y.y); } double operator * (const point &x,const point &y) { return x.x*y.y-y.x*x.y; } struct line{ point *p1,*p2; double k,b; void get_function() { point p=(*p2)-(*p1); k=(double)p.y/p.x; b=p1->y-k*p1->x; } double f(double x) { return k*x+b; } }lines[M]; int n; double ans,ansheight=1e11; double Rand() { return rand()%1000/1000.0; } bool Judge(point p) { int i; for(i=2;i<=n;i++) { if( (points[i-1]-p)*(points[i]-p)<0 ) return false; } return true; } double f(double x) { int i; for(i=2;i<=n;i++) if( x>=lines[i].p1->x && x<=lines[i].p2->x ) return lines[i].f(x); } double Divide(double x) { double l=0,r=1e11; double mid=(l+r)/2; while(r-l>1e-7) { if( Judge( point(x,mid) ) ) r=mid; else l=mid; mid=(l+r)/2; } mid-=f(x); if(mid<ansheight) ans=x,ansheight=mid; return mid; } void SA(double T) { int i; double Now=ans; for(;T>0.00001;T*=0.99) { double Neo=Now+T*(Rand()*2-1); if( Neo<points[1].x || Neo>points[n].x ) continue; double dE = Divide(Now) - Divide(Neo); if( dE>0 || exp(dE/T)>Rand() ) Now=Neo; } for(i=1;i<=1000;i++) { double Neo=ans+T*(Rand()*2-1); if( Neo<points[1].x || Neo>points[n].x ) continue; Divide(Neo); } } int main() { srand(19980406); int i; cin>>n; for(i=1;i<=n;i++) scanf("%lf",&points[i].x); for(i=1;i<=n;i++) scanf("%lf",&points[i].y); for(i=2;i<=n;i++) lines[i].p1=&points[i-1],lines[i].p2=&points[i],lines[i].get_function(); ans=(points[n].x+points[1].x)/2.0; SA( points[n].x-points[1].x ); printf("%.3lf\n",ansheight+1e-7); }
时间: 2024-10-13 11:56:11