【模拟退火入门】1:Country Meow 2:经典问题:旅行商问题 3:求多项式最值

学习博客:

https://www.cnblogs.com/zwfymqz/archive/2018/04/28/8966901.html

https://blog.csdn.net/baimafujinji/article/details/6474567

https://www.cnblogs.com/caijiaming/p/11674182.html

https://www.cnblogs.com/cieusy/p/9871095.html

https://blog.csdn.net/qq_18343569/article/details/50300147


 

模拟退火

定义:

         模拟退火算法(Simulate Anneal,SA)是一种通用概率演算法,用来在一个大的搜寻空间内找寻命题的最优解

变量:

         T:当前温度,从高温到低温,也就是从不稳定状态到稳定状态,代表算法进行到了什么程度

          ΔT:每次的温度变化率,一般取0.95-0.99,模拟退火过程,上次的温度×ΔT=当前的温度

          

算法流程:

①:枚举温度T

②:计算下一步的状态

③:若下一步的状态比当前状态优或者满足进行转移的条件就进行转移

④:降温

 

 

 


1:Country Meow

题意:

         求三维坐标下包围n个点的最小的球的半径

 

题解:

        每次找到一个距离当前点最远的点,作为可转移的下一个状态,

         概率Δp=(据当前位置最远的点-当前点的位置)/初始状态

 

代码

//#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
#pragma GCC optimize(2)
#define debug cout<<"*"< pii;
typedef pair pll;
typedef pair psi;
typedef pair pcc;
const int mod=1e9+7;
const int INF=1e9+7;
const int maxn=1e6+7;
const double PI=acos(-1);
const double K=1.380649e-23;    //玻尔兹曼常数
const int N=4;





//本题代码:

const double FINF=1e18+7;    
const int Init_temper=60000;    //初始温度
double eps=1e-6;                //控制结束条件,随题目不同而改变
double rate=0.99;                //以一定速率降低,通常为0.95-0.99,越大结果越精确,但是很慢




struct Node
{
    double x,y,z;
    Node(){}
    Node(double x1,double y1,double z1)
    {
        x=x1;y=y1;z=z1;
    }
}dot[maxn];


double len(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 solve(int n)
{
    double ans=FINF;
    double T=Init_temper;    //初始状态
    Node cur=Node(0,0,0);    //定义当前点的坐标,开始可以随机坐标
    Node max_dot=dot[1];    //定义最远距离的坐标
    while(T>eps)
    {
        for(int i=1;i<=n;i++)    //遍历找最远的点
        {
            if(len(dot[i],cur)>=len(cur,max_dot))
                max_dot=dot[i];
        }
        //满足转移的条件
        ans=min(ans,len(cur,max_dot));
        //降温过程
        cur.x=(cur.x+(max_dot.x-cur.x)*(T/Init_temper));
        cur.y=(cur.y+(max_dot.y-cur.y)*(T/Init_temper));
        cur.z=(cur.z+(max_dot.z-cur.z)*(T/Init_temper));
        
        T*=rate;    //逐渐趋于稳定
    }

    return ans;
}

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lf",&dot[i].x);
        scanf("%lf",&dot[i].y);
        scanf("%lf",&dot[i].z);
    }
    //solve();
    printf("%.15lf\n",solve(n));

    return 0;
}

 

 


 

旅行商问题:

还不会,直接放网上找的代码了,当模板用了

#include 
#include 
#include 
using namespace std;

#define MAX_CITY_NUM 100
#define T0 2000
#define T 1e-5
#define ALPHA 0.98
#define L 20000

struct path{
    int route[MAX_CITY_NUM];
    double dis;
};

double w[MAX_CITY_NUM][MAX_CITY_NUM];
int num;
double s = 0;
path p0;

void Init_City()
{
    cout << "Please input the number of cities:" << endl;
    cin >> num;
    for (int i = 0; i < num; ++i)
        for (int j = 0; j < num; ++j)
            cin >> w[i][j];
}

void Init_path()
{
    p0.dis = 0;
    for (int i = 0; i < num; ++i)
    {
        p0.route[i] = i;
        if (i != num - 1)
            p0.dis += w[i][i + 1];
    }
    p0.dis += w[num - 1][0];
}

path generate(path p)
{
    int x = 0, y = 0;
    while (x == y)
    {
        x = (int)(num * (rand() / (RAND_MAX + 1.0)));
        y = (int)(num * (rand() / (RAND_MAX + 1.0)));
    }
    path gen = p;
    int tmp;
    tmp = gen.route[x];
    gen.route[x] = gen.route[y];
    gen.route[y] = tmp;

    gen.dis = 0;
    for (int i = 0; i < num - 1; ++i)
        gen.dis += w[gen.route[i]][gen.route[i + 1]];
    gen.dis += w[gen.route[num - 1]][gen.route[0]];
    return gen;
}



void TSP_SA()
{
    double t = T0;
    srand(time(NULL));
    path cur = p0;
    path next = p0;
    int bChange;
    while (t > T)
    {
        bChange = 0;
        for (int i = 0; i < L; ++i)
        {
            next = generate(cur);
            double df = next.dis - cur.dis;
            if (df <= 0)
            {
                cur = next;
                bChange = 1;
            }
            else
            {
                double rndp = rand() / (RAND_MAX + 1.0);
                double eps = exp(-df / t);
                if (eps > rndp && eps < 1)
                {
                    cur = next;
                    bChange = 1;
                }
            }

        }

        if (cur.dis < p0.dis)
            p0 = cur;

        t *= ALPHA;
        if (!bChange)
            ++s;
        else
            s = 0;

        if (s == 2)
            break;
    }
}

int main()
{
    Init_City();
    Init_path();
    TSP_SA();

    cout << "The best path is:" << endl;
    for (int i = 0; i < num; ++i)
            cout << p0.route[i] << " -> ";
    cout << p0.route[0] << endl;
    cout << "The distance of the best path is: " << p0.dis << endl;
    system("pause");
    return 0;
}

 

 


 

3:多项式最值问题:

还是不会,回头填坑。。

 

#include
#include
#include
#include
#include
#include
#include
using namespace std;

#define ITERS 10
#define T 100
#define eps 1e-8
#define delta 0.98
#define INF 1e99

double x[ITERS];
int judge(double x, double y)
{
	if (fabs(x - y) < eps) return 0;
	return x < y ? -1 : 1;
}

double random()
{
	double x = rand()*1.0 / RAND_MAX;
	if (rand() & 1) x *= -1;
	return x;
}

double F(double x, double y)
{
	return 6 * pow(x, 7) + 8 * pow(x, 6) + 7 * pow(x, 3) + 5 * pow(x, 2) - x*y;
}
void init()
{
	for (int i = 0; i < ITERS; i++)
	{
		x[i] = fabs(random()) * 100;
	}
}

double sa(double y)
{
	double ans = INF;
	double t = T;
	while (t < eps)
	{
		for (int i = 0; i < ITERS; i++)
		{
			double tmp = F(x[i], y);
			for (int j = 0; j < ITERS; j++)
			{
				double _x = x[i] + random()*t;
				if (judge(_x, 0) >= 0 && judge(_x, 100) <= 0)
				{
					double f = F(_x, y);
					if (tmp>f)
						x[i] = _x;
				}
			}
		}
		t = t*delta;
	}
	for (int i = 0; i < ITERS; i++)
	{
		ans = min(ans, F(x[i], y));
	}
	return ans;
}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		double y;
		cin >> y;
		srand(time(NULL));
		init();
		cout << sa(y) << endl;
	}
	return 0;
}

 

你可能感兴趣的:(几何)