Country Meow (模拟退火)
模拟退火:
- 核心就是通过局部最优,然后随机跳出这个局部,找下一个最优解
- 通过物理的那个思想
- 核心元素: T=2000,(一般2000-5000) rate=0.996, limt 最低T,更具题目来看(在满足题目条件的情况下,多次循环)
代码:

void th() { node ans; ans.x=0;ans.y=0;ans.z=0; ANS=get(ans); while(T>lmt) { node t; t.x=ans.x+((rand()<<1)-RAND_MAX)*T; t.y=ans.y+((rand()<<1)-RAND_MAX)*T; t.z=ans.z+((rand()<<1)-RAND_MAX)*T; double tmp=get(t); // 上面是 计算下一个步的 函数值. double de=tmp-ANS; // 和当前的最优答案比较,更新 if(de<0) // 比他优化,就更新 { ANS=tmp; ans=t; } else if(exp((-de)/T)*RAND_MAX>rand()) ans=t; // 不然就随机看是否跳出跳出这个范围,进行更新, 然后 要保证()/T 是负数(通过是否加负号的方式) T*=rate; // 退火 } }
好好看看那个2个 关于随机的代码, srand(time(0)),和 rand(),记得写.
题目: 大意, 求一个球包裹所有点的最小半径
2022—暑假1 - Virtual Judge (vjudge.net)
本题代码:

#include <bits/stdc++.h> using namespace std; #define M 100005 #define ri register int int n,m; struct node { double x; double y; double z; }p[M]; double T=2000; double rate=0.996; double lmt=1e-300; double gg(node a,node b) { return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z)); } double get(node a) { double mx=0; for(ri i=1;i<=n;i++) { mx=max(mx,gg(a,p[i])); } return mx; } double ANS; void th() { node ans; ans.x=0;ans.y=0;ans.z=0; ANS=get(ans); while(T>lmt) { node t; t.x=ans.x+((rand()<<1)-RAND_MAX)*T; t.y=ans.y+((rand()<<1)-RAND_MAX)*T; t.z=ans.z+((rand()<<1)-RAND_MAX)*T; double tmp=get(t); // 上面是 计算下一个步的 函数值. double de=tmp-ANS; // 和当前的最优答案比较,更新 if(de<0) // 比他优化,就更新 { ANS=tmp; ans=t; } else if(exp((-de)/T)*RAND_MAX>rand()) ans=t; // 不然就随机看是否跳出跳出这个范围,进行更新, 然后 要保证()/T 是负数(通过是否加负号的方式) T*=rate; // 退火 } } int main(){ ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); srand(time(0)); rand(); cin>>n; for(ri i=1;i<=n;i++) cin>>p[i].x>>p[i].y>>p[i].z; th(); cout<<ANS; }