1 条题解
-
0
自动搬运
来自洛谷,原作者为

CR_Raphael
童年遗留,好羞耻搬运于
2025-08-24 22:02:10,当前版本为作者最后更新于2019-01-26 20:40:15,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
我怕不是个傻子
一道模版题肝模拟退火。
-孩子沉迷退火怎么办?逼他用模拟退火做计算几何再让他打正解,妈妈再也不用担心我的常数啦!咳,说正解,旋转卡壳求凸包点边最长值,
不过朕的代码……我一开始想歪了……直接凸包+二分上了……似乎没见过这样搞的……
就是找凸包上每个边斜率在凸包另一侧的位置,就确定了离该边最远的点。其实如果用尺取法做的话,就等价于旋转卡壳了。
所以我独立发明了旋转卡壳?贴个超级丑的代码,希望正统旋转卡壳亲之信之,则几何之隆,可计日而待也。
懒得做正解了,如果您是初学者,想用这篇代码为蓝本学旋转卡壳,那么我建议换一篇题解。
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; const double pi = 3.1415926535; const int maxn = 100005; const double inf = 2000000001; int n; double k, l, ans; int t; struct pointt { double x, y, tk; } a[maxn], p[maxn]; int findd(double ff) { int l, r, mid; l=1; r=t; while(l < r) { mid=(l+r+1)/2; if(a[mid].tk <= ff) l=mid; else r=mid-1; } return l; } double count_ans(int kx) { int i; double kk=a[kx].tk, maxx, minn; double kt; if(kk < pi) kk+=pi; else kk-=pi; if((a[kx].x!= a[kx-1].x)) kt=(a[kx].y-a[kx-1].y)/(a[kx].x-a[kx-1].x); else kt=inf; i=findd(kk); maxx=(kt*a[i].x-a[i].y)/sqrt(kt*kt+1); minn=(kt*a[kx].x-a[kx].y)/sqrt(kt*kt+1); if(kt == inf) { maxx=a[i].x; minn=a[kx].x; } return abs(maxx-minn)/2; } bool cmp(pointt a1, pointt a2) { return a1.tk < a2.tk; } double count(pointt a1, pointt a2) { double tt=atan2((a1.y-a2.y), (a1.x-a2.x)); if(tt < 0) tt+=2*pi; return tt; } double ll(pointt a1, pointt a2) { return sqrt((a1.y-a2.y)*(a1.y-a2.y) + (a1.x-a2.x)*(a1.x-a2.x)); } int main() { int i, minp, maxp; double miny; scanf("%d", &n); for(i=1; i <= n; i++) scanf("%lf%lf", &p[i].x, &p[i].y); miny=p[1].y; minp=1; for(i=1; i <= n; i++) { if(p[i].y < miny) miny=p[i].y, minp=i; } swap(p[1], p[minp]); for(i=1; i <= n; i++) p[i].tk=atan2(p[i].y-p[1].y, p[i].x-p[1].x); sort(p+1, p+1+n, cmp); t=0; i=0; do { i++; if(i == n+1) i=1; while(t > 1 && (count(p[i], a[t]) < count(a[t], a[t-1]))) { t--; } t++; a[t]=p[i]; a[t].tk=count(a[t], a[t-1]); } while(i != 1 || t <= 1); miny=inf; a[1].tk = -0.1; for(i=2; i <= t; i++) { miny=min(miny, count_ans(i)); } printf("%.2lf\n", miny); return 0; }另外呢,将军退火,性行淑均,适用于昔日,评测机称之曰90,愚以为此做题之法,仅供观赏,诸将切勿惫怠。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<ctime> using namespace std; const int maxn = 100005; const double maxl = 200000000; const double pai = 3.14159; const double delta=0.9; int n; double a[maxn], b[maxn], t; double ansp, ansk; int ts; double count(double k) { int i; double ll, maxx=-maxl, minn=maxl; for(i=1; i <= n; ++i) { ll=k*a[i]-b[i]; minn=min(minn, ll); maxx=max(maxx, ll); } maxx=maxx/sqrt(k*k+1); minn=minn/sqrt(k*k+1); return (maxx-minn)/2; } void SA() { double kk=ansk; double tk, newp; t=1777; while(t > 1e-14) { tk=kk+(rand()*2.0-RAND_MAX)*1.0/10000*t; newp=count(tan(tk)); //cout<<tk<<' '<<newp<<endl; //cin>>ts; if(newp < ansp) { kk=tk; ansk=tk; ansp=newp; } else if(exp(-(newp-ansp)*1000/t)*RAND_MAX > rand()) { kk=tk; } t*=delta; } return; } int main() { srand(time(NULL)); scanf("%d", &n); //cout<<RAND_MAX<<endl; int i; double pi, tt, stt; for(i=1; i <= n; ++i) { scanf("%lf%lf", &a[i], &b[i]); } //cout<<count(1)<<endl; ansk=0; ansp=count(tan(ansk)); for(pi=-1.6; pi <= 1.6; pi+=0.01) { tt=count(tan(pi)); if(tt < ansp) { ansp=tt; ansk=pi; } } stt=ansk; for(pi=stt-0.1; pi <= stt+0.1; pi+=0.001) { tt=count(tan(pi)); if(tt < ansp) { ansp=tt; ansk=pi; } } stt=ansk; for(pi=stt-0.01; pi <= stt+0.01; pi+=0.0001) { tt=count(tan(pi)); if(tt < ansp) { ansp=tt; ansk=pi; } } stt=ansk; for(pi=stt-0.001; pi <= stt+0.001; pi+=0.00001) { tt=count(tan(pi)); if(tt < ansp) { ansp=tt; ansk=pi; } } SA(); printf("%.2lf\n", ansp); return 0; }
- 1
信息
- ID
- 3612
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者