专栏文章

【模板】三分 | 函数 使用 SA 解决

P1883题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@min4c9uj
此快照首次捕获于
2025/12/01 20:21
3 个月前
此快照最后确认于
2025/12/01 20:21
3 个月前
查看原文
我们来分析一下这个题。
就这么说,虽然你能够用这个那个数学方法来证明出这是一个单峰函数,但是很多时候如果没有“三分”这个标签,你压根就想不出来这道题是单峰函数。
所以我们可以用模拟退火来解决这道题(调参调了一天)。
这道题因为较为简单,所以可以设置较为激进的降温策略。初始温度设置一个最平常的 4000 就可以了。
其他的就跟 SA 的模板是差不多的了。
AC 代码:
CPP
#include <bits/stdc++.h>
using namespace std;
const double down=0.9943; // 可以设置激进一点的降温速度
int n;
struct node{
	double x,y,w;
}a[10005];
double dx,now;
double energy(double x)
{
	double tot=-1e20; // 注意 f(x) 可能为负数
	for(int i=1; i<=n; i++)
	{
		tot=max(tot,a[i].x*x*x+a[i].y*x+a[i].w);
	}
	return tot;
}
void SA()
{
	double t=4000;
	while(t>1e-17)
	{
		double tx=dx+(rand()*2-RAND_MAX)*t;
		if(tx<0) tx=(rand()%100);
		if(tx>1000) tx=(1000);
		
      	double temp=energy(tx);
      	double delte=temp-now;
      	if(delte<0)
      	{
      		dx=tx;
      		now=temp;
		  }
		else if(exp(-delte/t)*RAND_MAX>rand())
		{
			dx=tx;
		}
		t*=down;
	}
}
void sjk()
{
	cin>>n;
	for(int i=1; i<=n; i++)
	{
		cin>>a[i].x>>a[i].y>>a[i].w;
	}
	dx=500;
	now=energy(dx);
	SA();
	cout<<fixed<<setprecision(4)<<energy(dx)<<endl;
}
int main()
{
	int t;
	cin>>t;
	while(t--) sjk();
	return 0;
} 
但是我们悲催的发现,只有吸氧可以过这个代码,不然只有 50 分。
怎么办!
打正解?No way!
温度?30003000 就够!
降温速度?0.8850.885 就行
ACcode(不吸氧):
CPP
#include <bits/stdc++.h>
using namespace std;
const double down=0.885;
int n;
struct node{
	int  x,y,w;
}a[10005];
double dx,now;
double energy(double x)
{
	double tot=-1e20;
	for(int i=1; i<=n; i++)
	{
		tot=max(tot,a[i].x*x*x+a[i].y*x+a[i].w);
	}
	return tot;
}
void SA()
{
	double t=3000;
	while(t>1e-17)
	{
		double tx=dx+(rand()*2-RAND_MAX)*t;
		if(tx<0) tx=0;
		if(tx>1000) tx=(1000);
		
      	double temp=energy(tx);
      	double delte=temp-now;
      	if(delte<0)
      	{
      		dx=tx;
      		now=temp;
		  }
		else if(exp(-delte/t)*RAND_MAX>rand())
		{
			dx=tx;
		}
		t*=down;
	}
}
void sjk()
{
	cin>>n;
	for(int i=1; i<=n; i++)
	{
		cin>>a[i].x>>a[i].y>>a[i].w;
	}
	dx=500;
	now=energy(dx);
	SA();
	cout<<fixed<<setprecision(4)<<energy(dx)<<endl;
}
int main()
{
	int t;
	cin>>t;
	while(t--) sjk();
	return 0;
} 
一段 模拟退火
一台 电脑
一个夜晚
一个又 WA 又 TLE 的记录

评论

0 条评论,欢迎与作者交流。

正在加载评论...