• 模拟退火


    如图所示。

    退火算法,爬山算法都是一种复杂度低,但是能得到近似解的算法。

    其中爬山算法其实就是梯度下降,可能会陷入局部最优。

    1. 爬山算法:兔子朝着比现在高的地方跳去。它找到了不远处的最高山峰。但是这座山不一定是珠穆朗玛峰。这就是爬山算法,它不能保证局部最优值就是全局最优值。
    2. 模拟退火:兔子喝醉了。它随机地跳了很长时间。这期间,它可能走向高处,也可能踏入平地。但是,它渐渐清醒了并朝最高方向跳去。这就是模拟退火。

    根据热力学规律并结合计算机对离散数据的处理, 我们定义: 如果当前温度为 (T), 当前状态与新状态之间的能量差为 (ΔE), 则发生状态转移的概率为:

    [P(Delta E) = e^{dfrac {Delta E} {T}} ]

    (Delta E) 为正的时候一定是转移成功的,对于 $Delta E < 0 $ , 则通过计算的概率接受这个新的解

    可以写出如下一段伪代码

    void mnth(){ //模拟退火...
    	for(double T = 初始温度;T > 终止温度;T *= 系数){
    		rand_operate();//做一个随机操作
    		now = cal(); //计算目前的答案
    		if(now < ans) ans = now;//若更优,直接转移
    		else if(exp((ans - now) / T) * RAND_MAX < rand()){
                //这里写的是小于号,是不转移
    			//不转移,撤销刚刚的随机操作
    		}
    	}
    }
    

    看两道题

    P1337 [JSOI2004]平衡点 / 吊打XXX

    其实就是选一个点,使得这个点到所有点的距离乘上质量之和要最小

    相当于在二维的平面找一个最优解

    #include<bits/stdc++.h>
    #define N 2000
    using namespace std;
    
    struct node
    {
    	double x, y, w;
    }e[N];
    int n;
    double ansx, ansy;
    const double eps = 1e-15;
    double f(double x, double y)
    {
    	double tot = 0;
    	for (int i = 1; i <= n; i++){
    		double delx = x - e[i].x;
    		double dely = y - e[i].y;
    		tot += sqrt(delx * delx + dely * dely) * e[i].w;
    	}
    	return tot;
    }
    void mnth()
    {
    	for(double T = 5000;T > 1e-15;T *= 0.995){
    		double nowx = ansx + (rand() * 2 - RAND_MAX) * T;
    		double nowy = ansy + (rand() * 2 - RAND_MAX) * T;
    		double delta = f(nowx, nowy) - f(ansx, ansy);
    		if (delta < 0)ansx = nowx, ansy = nowy;
    		else if (exp(-delta / T)> rand()*1.0/RAND_MAX)ansx = nowx, ansy = nowy;
    	}
    }
    int main(){
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i++){
    		scanf("%lf%lf%lf", &e[i].x, &e[i].y, &e[i].w);
    		ansx += e[i].x; ansy += e[i].y;
    	}
    	ansx /= (double)n; ansy /= (double)n;
    	mnth();
    	printf("%.3lf %.3lf
    ", ansx, ansy);
    }
    

    P3878 [TJOI2010]分金币

    现在有 (n) 枚金币,它们可能会有不同的价值,第 (i) 枚金币的价值为 (v_i)

    现在要把它们分成两部分,要求这两部分金币数目之差不超过 1 ,问这样分成的两部分金币的价值之差最小是多少?

    每次随机交换两个元素

    当时这里的小于号和大于号弄混了,调了好久

    #include<bits/stdc++.h>
    using namespace std;
    
    int ans, T, n, A[50];
    
    int get() {
    	int sum = 0;
    	for (int i = 0; i < n; i++) {
    		if (i < n / 2)sum += A[i];
    		else sum -= A[i];
    	}
    	return abs(sum);
    }
    
    void mnth() {
    	for (double T = 5000; T > 1e-15; T *= 0.945) {
    		int x = rand() % n, y = rand() % n;
    		swap(A[x], A[y]); int now = get();
    		if (now < ans) ans = now;
    		else if (exp((ans - now) / T) * RAND_MAX < rand()) swap(A[x], A[y]); // > 是转移, < 是撤销
    	}
    }
    
    int main() {
    	scanf("%d", &T);
    	while (T--) {
    		scanf("%d", &n);
    		for (int i = 0; i < n; i++)scanf("%d", A + i);
    		ans = 0x7fffffff; int x = 1000; while (x--)mnth();
    		printf("%d
    ", ans);
    	}
    }
    
  • 相关阅读:
    国外高手又一力作,CAML Builder
    用word2007发布blog!!
    SharePoint Server 2007 trial 年末大餐细细品尝 (第八口)
    SharePoint Server 2007 trial 年末大餐细细品尝 (再来一口)
    SharePoint Server 2007 trial 年末大餐细细品尝 (第三口)
    SharePoint Server 2007 trial 年末大餐细细品尝 (第十口)
    卡壳了~~~
    SharePoint Server 2007 trial 年末大餐细细品尝 (第九口)
    moss 与 ad 用户信息不同步的问题。
    SharePoint Server 2007 trial 年末大餐细细品尝 (第六口)
  • 原文地址:https://www.cnblogs.com/sduwh/p/13900669.html
Copyright © 2020-2023  润新知