本校OJ过的,附个Libre链接:https://loj.ac/problem/2076#submit_code
看懂题面想了一会应该是个搜索题,没啥头绪
偷偷上baidu瞄了眼题解
模模模模模拟退火??
...
陷入了人生的大思考
思考良久决定换一篇题解
还是模拟退火
...
强忍着换题的欲望开始找板子
好在板子好像也是二维搜索?几分钟就改好了
重点在将energy()
函数改成需要的目标函数
(exp(-de / t) * RAND_MAX < rand())
中间的比较符要与上面(de > 0)
的符号相反
别的就没啥了,开始调参
在本校OJ交之前先去Libre上调参调了半小时
附个找到的板子
#include <bits/stdc++.h>
#define down 0.996//徐徐降温
using namespace std;
int n;
struct node{
int x;
int y;
int w;
}object[2005];//存下物体的坐标
double ansx,ansy,answ;//最终答案
double energy(double x,double y)//根据物理学知识,能量总和越小越稳定
{
double r=0,dx,dy;
for (int a=1;a<=n;a++)
{
dx=x-object[a].x;
dy=y-object[a].y;
r+=sqrt(dx*dx+dy*dy)*object[a].w;
}
return r;
}
void sa()//模拟退火
{
double t=3000;//温度要足够高
while (t>1e-15)//略大于0
{
double ex=ansx+(rand()*2-RAND_MAX)*t;//随机产生新的答案
double ey=ansy+(rand()*2-RAND_MAX)*t;
double ew=energy(ex,ey);
double de=ew-answ;
if (de<0)//如果此答案更优,就接受
{
ansx=ex;
ansy=ey;
answ=ew;
}
else if(exp(-de/t)*RAND_MAX>rand())//否则根据多项式概率接受
{
ansx=ex;
ansy=ey;
}
t*=down;
}
}
void solve()//多跑几遍退火,增加得到最优解的概率
{
sa();
sa();
sa();
sa();
}
int main() {
cin>>n;
for (int a=1;a<=n;a++)
{
scanf("%d%d%d",&object[a].x,&object[a].y,&object[a].w);
ansx+=object[a].x;
ansy+=object[a].y;
}
ansx/=n;//以平均数作为初始答案
ansy/=n;
answ=energy(ansx,ansy);
solve();
printf("%.3lf %.3lf\n",ansx,ansy);//华丽的输出
return 0;
}
code
#include <bits/stdc++.h>
#define numm ch-48
#define pd putchar(' ')
#define pn putchar('\n')
#define pb push_back
#define fi first
#define se second
#define fre1 freopen("1.txt","r",stdin)
#define fre2 freopen("2.txt","w",stdout)
typedef long long int ll;
typedef long long int LL;
using namespace std;
template<typename T>
void read(T &res) {
bool flag = false;
char ch;
while (!isdigit(ch = getchar())) (ch == '-') && (flag = true);
for (res = numm; isdigit(ch = getchar()); res = (res << 1) + (res << 3) + numm);
flag && (res = -res);
}
template<typename T>
void write(T x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
//static auto _ = []()
//{
// ios::sync_with_stdio(false);
// cin.tie(0);
// return 0;
//}();
//
#define down 0.996
int n, m, r;
struct bui {
int x, y, r;
} a[15];
struct node {
int x;
int y;
} b[1005];
double ansx, ansy, answ;
double dist(double x1, double y1, double x2, double y2) {
return sqrt(fabs((x1 - x2) * (x1 - x2)) + fabs((y1 - y2) * (y1 - y2)));
}
int energy(double x, double y) {
int sum = 0;
double rr = r;
for (int i = 1; i <= n; i++) {
double dis = dist(x, y, a[i].x, a[i].y) - a[i].r;
rr = min(rr,dis);
}
for(int i = 1; i<=m;i++){
double dis = dist(x,y,b[i].x,b[i].y);
if(dis <= rr){
sum++;
}
}
return sum;
}
void sa()//模拟退火
{
double t = 5000;//温度要足够高
while (t > 1e-15)//略大于0
{
double ex = ansx + (rand() * 2 - RAND_MAX) * t;//随机产生新的答案
double ey = ansy + (rand() * 2 - RAND_MAX) * t;
int ew = energy(ex, ey);
int de = ew - answ;
if (de > 0)//如果此答案更优,就接受
{
ansx = ex;
ansy = ey;
answ = ew;
} else if (exp(-de / t) * RAND_MAX < rand())//否则根据多项式概率接受
{
ansx = ex;
ansy = ey;
}
t *= down;
}
}
void solve()//多跑几遍退火,增加得到最优解的概率
{
sa();
sa();
sa();
sa();
sa();
sa();
}
int main() {
read(n), read(m), read(r);
for (int i = 1; i <= n; i++) {
read(a[i].x), read(a[i].y), read(a[i].r);
}
for (int i = 1; i <= m; i++) {
read(b[i].x), read(b[i].y);
ansx += b[i].x;
ansy += b[i].y;
}
ansx /= m;
ansy /= m;
solve();
write((int) answ);
return 0;
}