Simulated annealing learning notes

Randomization algorithm has no future

brief introduction

Simulated annealing is a randomized (metaphysical) algorithm. It is widely used in all kinds of deception methods for finding the maximum value. In short, for a multimodal function, if its maximum value is required, it can be solved by simulated annealing.

Of course, if it is directly random, the accuracy is obviously very low. However, in general practical problems, even if the function has no definite monotonicity, the difference of the function in an interval will not be too large. Therefore, simulated annealing can be used to optimize this process (which can be understood as heuristic search algorithm).

concept

temperature

In simulated annealing, the most important concept is temperature, which can also be understood as the current randomized interval. Temperature is a decreasing process, so every random interval will continue to narrow, and finally approach a point.

Initial temperature, termination temperature, attenuation coefficient

The initial temperature is the initial temperature at the beginning (for example, if the initial interval is \ (10 ^ 5 \), the initial temperature can be set to \ (5 \times 10^4 \)), the termination temperature is the temperature at the end of the algorithm, and the attenuation coefficient is the coefficient of each temperature reduction. Generally speaking, the attenuation coefficient will take a decimal point in \ (0 \sim 1 \) (the so-called parameter adjustment is to change the attenuation coefficient. Generally speaking, the accuracy can be increased by parameter adjustment).

Of course, in the formal competition, because the running time of each program is also random, the card time method can be used to determine the random times.

Select a point at random

Take the global minimum value as an example. In each annealing process, a point will be randomly selected within the current temperature range, the function value of the point will be calculated, and the difference between the function value of the new point and the original function value is \ (\ Delta E \). Next, we will discuss the classification according to the value of \ (\ Delta E \):

1. \ (\ delta e < 0 \), then the new point must be better than the origin and jump to this point.

2. \ (\ delta E > 0 \), then jump to a new point with a certain probability. Because the original function is not unimodal, if you only jump to points smaller than the current point function value, you may jump to a local minimum instead of a global minimum. At this time, the skip probability can be set as \ (e^{\frac{-\Delta E}{T} \) according to the empirical value, where \ (T \) represents the current temperature. (according to the nature of exponential function, the probability set in this way must be between \ (0 \sim 1 \), and the lower the difference, the higher the probability of jumping over, and vice versa. This is also in line with the actual process).

[template] A Star not a Tree?

Given a polygon, find a point to minimize the sum of distances from this point to all vertices.

Data range

\(n \leq 100\).

thinking

Through various proofs, we can know that the function image of this problem is a convex function, which can be solved by trisection. However, in order to implement the spirit of chaos and learn simulated annealing algorithm, simulated annealing is used to solve this problem.

It can be written directly according to the concepts mentioned above. The probability of error can also be reduced by multiple simulations.

code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<ctime>
using namespace std;
const int N=110;
struct node{double x,y;}p[N];
int n;double ans=1e15;
double dis(node a,node b){double dx=a.x-b.x,dy=a.y-b.y;return sqrt(dx*dx+dy*dy);}
double calc(node a){double res=0;for(int i=1;i<=n;i++) res+=dis(a,p[i]);ans=min(ans,res);return res;}//Don't forget to update your answers every time 
double rand(double l,double r)//A random number in l and r 
{
	return 1.0*rand()/RAND_MAX*(r-l)+l;
}
void simulate_anneal()
{
	node now=node{rand(0,10000),rand(0,10000)};
	double S=1e4,T=1e-14,K=0.995;//Start temperature, end temperature, attenuation coefficient 
	for(double t=S;t>T;t*=K)
	{
		node tmp=node{rand(now.x-t,now.x+t),rand(now.y-t,now.y+t)};
		double delta=calc(tmp)-calc(now);
		if(exp(-delta/t)>rand(0,1)) now=tmp;
	}
}
int main()
{
	srand(time(0));int T;scanf("%d",&T);
	while(T--)
	{
		ans=1e18;scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%lf%lf",&p[i].x,&p[i].y);
		for(int i=0;i<=10;i++) simulate_anneal();printf("%.0lf\n",ans);if(T) puts("");
	}
	return 0;
}

[application] bowling

The background of this topic is more complex. It is suggested to look at the background of the original topic directly. After understanding the meaning of the question, you can find that the original binary is rearranged to maximize the total score.

thinking

Simulated annealing can also solve the problem of optimal solution, but it needs to ensure that each operation will not change the function value too much. For example, in this question, the change in the answer will not be particularly large after exchanging the game twice. Then we can exchange two subscripts randomly at a time according to the general idea, and then judge whether the exchange can be carried out according to the difference and randomization before and after the exchange.

code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<ctime>
#include<cstdlib> 
using namespace std;
const int N=110;
int n,m,ans;
struct node{int a,b;}q[N];
int calc()
{
	int res=0;
	for(int i=1;i<=m;i++)
	{
		res+=q[i].a+q[i].b;if(i==m) continue;
		if(q[i].a==10) res+=q[i+1].a+q[i+1].b;
		else if(q[i].a+q[i].b==10) res+=q[i+1].a;
	}
	ans=max(ans,res);return res;
}
double rand(double l,double r){return 1.0*rand()/RAND_MAX*(r-l)+l;}
void simulate_anneal()
{
	double S=1e5,T=1e-10,K=0.99;
	for(double t=S;t>T;t*=K)
	{
		int x=rand()%m+1,y=rand()%m+1,delta=-calc();swap(q[x],q[y]);
		if(n+(q[n].a==10)==m)//meaning of the title
		{
		    delta+=calc();
			if(exp(1.0*delta/t)<rand(0,1)) swap(q[x],q[y]);//Because it is the maximum value, there is no minus sign in the front bracket
		}
		else swap(q[x],q[y]);//If not, exchange it back
	}
}
int main()
{
	scanf("%d",&n);m=n;for(int i=1;i<=n;i++) scanf("%d%d",&q[i].a,&q[i].b);
	if(q[n].a==10) m++,scanf("%d%d",&q[m].a,&q[m].b);
	do{ simulate_anneal();} while(1.0*clock()<CLOCKS_PER_SEC*0.95);
	printf("%d\n",ans);
	return 0;
}

[application] Average data

Give the number of \ (n \), divide them into \ (m \) groups, and find their minimum mean square deviation.

Data range

\(1 \leq m \leq n \leq 20\).

thinking

It can be found that direct randomization of this problem seems not easy to do. Consider this problem first. If the first \ (n-1 \) numbers have been divided into \ (m \) groups. Then the last number must be placed in the group with the smallest sum of current values, and the mean square deviation will be the smallest. Perceptual understanding is not difficult. Strict mathematical proof can be consulted N total.

Then the original problem can be transformed into a rearrangement problem, which is similar to the method of the previous problem.

code:

#include<ctime>
#include<cmath>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=110;
double ans=1e15;
int n,m,a[N],s[N];
double ave;
double calc()
{
	memset(s,0,sizeof(s));
	for(int i=1;i<=n;i++)
	{
		int k=1;
		for(int j=2;j<=m;j++)
		    if(s[j]<s[k]) k=j;
		s[k]+=a[i];
	}
	double res=0;
	for(int i=1;i<=m;i++) res+=(1.0*s[i]-ave)*(1.0*s[i]-ave);
	res=sqrt(1.0*res/m);ans=min(ans,res);
	return res;
}
double rand(double l,double r){return 1.0*rand()/RAND_MAX*(r-l)+l;}
void simulate_anneal()
{
	double S=1e5,T=1e-5,K=0.996;
	for(double t=S;t>=T;t*=K)
	{
		int x=rand()%n+1,y=rand()%n+1;double delta=-calc();swap(a[x],a[y]);delta+=calc();
		if(exp(-1.0*delta/t)<rand(0,1)) swap(a[x],a[y]);
	}
}
int main()
{
	srand(time(0));scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),ave+=a[i];ave/=1.0*m;
	do{ simulate_anneal();} while(1.0*clock()<=CLOCKS_PER_SEC*0.95);
	printf("%.2lf\n",ans);
	return 0;
}

Tags: AcWing

Posted on Sun, 28 Nov 2021 12:13:30 -0500 by apitto