【BZOJ1038】【codevs1412】瞭望塔,半平面交/三分法
来源:互联网 发布:配电网工程设计软件 编辑:程序博客网 时间:2024/05/21 17:20
传送门1
传送门2
思路:
一开始看的时候感觉并没有什么直截了当的想法,想起在abclzr的博客里见到过这道题目,分类是半平面交,然后就往半平面交的方面上去想,发现塔顶的可行区域是一段下凸壳及其上面的区域,然后就有了一个想法,把可行区域求出来,然后最优选择一定是轮廓上的点往上到下凸壳或凸壳上的点往下到轮廓,当时的我只感觉这样是对的,造了一个数据,发现没有反例,然后就“大胆猜想,从不证明”地写了一发,而且很蠢地搞了一发
abclzr表示ljw(男)在去年的SD夏令营讲过这道题目,呃,蒟蒻表示没听过,也可能听过忘了吧。。。
后来看到BZOJ的discuss里有人说还可以三分,表示非常神奇,想了一会发现,对于轮廓上的每一段线段,它对应的分段函数区间一定是单峰的,因为它上方的下凸壳的线段连续且斜率递增,所以距离只能是递减,递增或先减后增,所以我们枚举每一段轮廓,在它上面三分一下位置,然后取较优值就可以了,复杂度
这道题目还有模拟退火的做法,蒟蒻表示没学过,不过一题多解这种想法在平常练习中还是很重要的,有利于拓展思维,增长见识,从不同的角度考虑问题,或许能得到新的思路和方法
#include<cstdio>#include<iostream>#include<cmath>#include<algorithm>#define eps 1e-8using namespace std; int n,be,ed;int X[305],Y[305];double ans=1e18;struct Point{ double x,y; Point(double X=0,double Y=0){x=X;y=Y;}};typedef Point Vec;Vec operator +(Vec a,Vec b){return Vec(a.x+b.x,a.y+b.y);}Vec operator -(Vec a,Vec b){return Vec(a.x-b.x,a.y-b.y);}Vec operator *(Vec a,double p){return Vec(a.x*p,a.y*p);}double cross(Vec a,Vec b){return a.x*b.y-a.y*b.x;}struct Line{ Point p; Vec v; double ang; Line(Point P=Point(0,0),Vec V=Vec(0,0)){p=P;v=V;ang=atan2(v.y,v.x);} bool operator <(const Line other)const { if (ang==other.ang) return v.x<other.v.x; return ang<other.ang; }}line[305],q[305];Point cp[305];int dcmp(double x){ if (fabs(x)<=eps) return 0; return x>0?1:-1;}bool onleft(Line a,Point b){ return dcmp(cross(b-a.p,a.v))<=0;}Point inter(Line a,Line b){ Point u=a.p-b.p; double t=cross(u,b.v)/cross(b.v,a.v); return a.p+a.v*t;}void SI(int n){ sort(line+1,line+n+1); int head=1,tail=0; for (int i=1;i<=n;++i) { while (head<tail&&!onleft(line[i],cp[tail-1])) --tail; while (head<tail&&!onleft(line[i],cp[head])) ++head; if (head<=tail&&dcmp(cross(line[i].v,q[tail].v))==0) if (onleft(q[tail],line[i].p)) q[tail]=line[i]; else; else q[++tail]=line[i]; if (head<tail) cp[tail-1]=inter(q[tail],q[tail-1]); } while (head<tail&&!onleft(q[head],cp[tail-1])) --tail; be=head,ed=tail-1; if (dcmp(cross(q[head].v,q[tail].v))==0); else ++ed,cp[tail]=inter(q[head],q[tail]);}main(){ scanf("%d",&n); for (int i=1;i<=n;++i) scanf("%d",X+i); for (int i=1;i<=n;++i) scanf("%d",Y+i); for (int i=2;i<=n;++i) line[i-1]=Line(Point(X[i-1],Y[i-1]),Vec(X[i]-X[i-1],Y[i]-Y[i-1])); line[n]=Line(Point(X[1],Y[1]),Vec(0,-1e6)); line[n+1]=Line(Point(X[n],Y[n]),Vec(0,1e6)); SI(n+1); double t; for (int i=1;i<=n;++i) for (int j=be;j<ed;++j) if (cp[j].x<=X[i]&&X[i]<=cp[j+1].x) ans=min(ans,t=fabs(inter(Line(cp[j],cp[j+1]-cp[j]),Line(Point(X[i],Y[i]),Vec(0,1))).y-Y[i])); for (int j=be;j<=ed;++j) for (int i=1;i<n;++i) if (X[i]<=cp[j].x&&cp[j].x<=X[i+1]) ans=min(ans,fabs(cp[j].y-inter(Line(Point(X[i],Y[i]),Vec(X[i+1]-X[i],Y[i+1]-Y[i])),Line(cp[j].x,Vec(0,-1))).y)); printf("%.3lf\n",ans);}
0 0
- 【BZOJ1038】【codevs1412】瞭望塔,半平面交/三分法
- [BZOJ1038]ZJOI2008瞭望塔|半平面交
- bzoj1038 瞭望塔 半平面交
- 【bzoj1038】【ZJOI2008】【瞭望塔】【半平面交】
- [半平面交] BZOJ1038: [ZJOI2008]瞭望塔
- bzoj1038 瞭望塔【半平面交】
- 【半平面交】【计算几何】[BZOJ1038][ZJOI2008]瞭望塔
- 【半平面交】[ZJOI2008][HYSBZ\BZOJ1038]瞭望塔
- [BZOJ1038][ZJOI2008]瞭望塔(半平面交)
- bzoj1038:[ZJOI2008]瞭望塔(半平面交)
- [BZOJ1038][ZJOI2008]瞭望塔(半平面交)
- [BZOJ1038][洛谷P2600]-[ZJOI2008]瞭望塔-半平面交
- bzoj1038 [ZJOI2008]瞭望塔(半平面交)
- 【BZOJ1038】[ZJOI2008]瞭望塔 计算几何 半平面交/模拟退火+二分
- ZJOI 2008 瞭望塔 半平面交
- ZJOI2008 瞭望塔 半平面交
- bzoj 1038 瞭望塔 半平面交 + 最小值 枚举
- BZOJ 1038 ZJOI2008 瞭望塔 半平面交
- 电脑硬件知识入门之显卡篇
- 【持续更新】adb常用命令
- react阻止冒泡事件(使用原生js方法)
- [我眼中的C#]XML和JSON
- Git 使用中显示“Another git process seems to be running in this repository...”问题解决
- 【BZOJ1038】【codevs1412】瞭望塔,半平面交/三分法
- ssh putty使用 记录
- mysql数据库中 控制流程函数 case
- mysql事件
- 迄今为止计算机视觉领域超有实力的研究人物主页
- service和aidl的区别
- java.lang.UnsatisfiedLinkError: no jacob in java.library.path
- 优先级队列-数据结构和算法
- Android ADB命令?这一次我再也不死记了!