模拟退火 (poj 2420, poj 2069)

模拟退火基本知识

其伪代码例如以下:

Let s = s0
For k = 0 through k_max (exclusive):
  T := temperature(k / k_max)
	Pick a random neighbour, s_new := neighbour(s)
	If P(E(s), E(s_new), T) > random(0, 1), move to the new state:
		s := s_new
Output: the final state s

样例:

poj 2420

题意:

平面上给你n个点(xi,yi),让你求一个点。到这n点的距离和最小。

限制:

1 <= n <= 100

0 <= xi,yi <= 1e4, 为整数

/*poj 2420
  题意:
  平面上给你n个点(xi,yi),让你求一个点,到这n点的距离和最小。
  限制:
  1 <= n <= 100
  0 <= xi,yi <= 1e4, 为整数
  思路:
  模拟退火

  模拟退火基本知识:
  其伪代码例如以下:
  Let s = s0
  For k = 0 through k_max (exclusive):
	T := temperature(k / k_max)
  	Pick a random neighbour, s_new := neighbour(s)
  	If P(E(s), E(s_new), T) > random(0, 1), move to the new state:
  		s := s_new
  Output: the final state s
*/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
using namespace std;
const double E = exp(1.0);
struct Pt{
	double x,y;
}p[105];
double sqr(double x){
	return x*x;
}
double dis(Pt a, Pt b){
	return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));
}
double get_sum(Pt p0, int n){
	double ret = 0;
	for(int i = 0; i < n; ++i)
		ret += dis(p0, p[i]);
   return ret;
}
int main(){
	srand(1123);
	int n;
	int limit = 10000; //(x,y)的范围
	while(scanf("%d", &n) != EOF){
		double x0 = 0, y0 = 0;
		for(int i = 0; i < n; ++i){
			scanf("%lf%lf", &p[i].x, &p[i].y);
			x0 += p[i].x;
			y0 += p[i].y;
		}
		x0 /= n;
		y0 /= n;
		double ans = get_sum((Pt){x0, y0}, n);
		double temp = 1e5; //初始温度, 依据题目改动
		while(temp > 0.02){ //0.02为温度的下限, 若温度temp达到下限, 则停止搜索
			double x = 0, y = 0;
			for(int i = 0; i < n; ++i){ //获取步长的规则依据题目而定
				x += (p[i].x - x0) / dis((Pt){x0, y0}, p[i]);
				y += (p[i].y - y0) / dis((Pt){x0, y0}, p[i]);
			}
			double tmp = get_sum((Pt){x0 + x * temp, y0 + y * temp}, n); //标函数E(x_new);
			if(tmp < ans){
				ans = tmp;
				x0 += x * temp;
				y0 += y * temp;
			} else if(pow(E, (ans - tmp) / temp) > (rand() % limit) / (double)limit){
				ans = tmp;
				x0 += x * temp;
				y0 += y * temp;
			}
			temp *= 0.9; //0.9为降温退火速率, (范围为0~1, 越大得到全局最优解的概率越高, 执行时间越长
		}
		printf("%.0f\n", ans);
	}
	return 0;
}

poj 2069 Super Star

题意:

给定n个点(xi, yi, zi), 要求覆盖这些点的最小球半径。

限制:

4 <= n <= 30

0 <= xi, yi, zi <= 100

/*poj 2069 Super Star
  题意:
  给定n个点(xi, yi, zi), 要求覆盖这些点的最小球半径。
  限制:
  4 <= n <= 30
  0 <= xi, yi, zi <= 100
  思路:
  模拟退火
 */
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
using namespace std;
const double E = exp(1.0);
struct Pt{
	double x, y, z;
}p[35];
double sqr(double x){
	return x * x;
}
double dis(Pt a, Pt b){
	return sqrt(sqr(a.x - b.x) +
				sqr(a.y - b.y) +
				sqr(a.z - b.z));
}
double get_max_r(Pt p0, int n){
	double ret = 0;
	for(int i = 0; i < n; ++i)
		ret = max(ret, dis(p0, p[i]));
	return ret;
}
int main() {
	int n;
	int limit = 100;
	while(scanf("%d", &n) && n){
		double x0 = 0, y0 = 0, z0 = 0;
		for(int i = 0; i < n; ++i){
			scanf("%lf%lf%lf", &p[i].x, &p[i].y, &p[i].z);
			x0 += p[i].x;
			y0 += p[i].y;
			z0 += p[i].z;
		}
		x0 /= n;
		y0 /= n;
		z0 /= n;
		//cout<<x0<<‘ ‘<<y0<<‘ ‘<<z0<<endl;
		double ans = get_max_r((Pt){x0, y0, z0}, n);
		double temp = 1e5;
		while(temp > 1e-8){
			double x = 0, y = 0, z = 0;
			double max_r = 0;
			for(int i = 0; i < n; ++i){
				double r = dis((Pt){x0, y0, z0}, p[i]);
				if(r > max_r){
					x = (p[i].x - x0) / r;
					y = (p[i].y - y0) / r;
					z = (p[i].z - z0) / r;
					max_r = r;
				}
			}
			double tmp = get_max_r((Pt){
					x0 + x * temp,
					y0 + y * temp,
					z0 + z * temp}, n);
			if(tmp < ans){
				ans = tmp;
				x0 += x * temp;
				y0 += y * temp;
				z0 += z * temp;
			} else if(pow(E, (ans - tmp) / temp) > (rand() % limit) / (double)limit){
				ans = tmp;
				x0 += x * temp;
				y0 += y * temp;
				z0 += z * temp;
			}

			temp *= 0.998;
		}
		printf("%.5f\n", ans);
	}
	return 0;
}
时间: 2024-10-23 12:34:09

模拟退火 (poj 2420, poj 2069)的相关文章

POJ 2420 A Star not a Tree? (模拟退火)

题目地址:POJ 2420 今天在比赛遇到了这题..于是现场学了一下模拟退火.... 这题是先初始化为一个点,然后不断趋近距离和最短的点.还是挺简单的.. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctype.h&g

POJ 2420 模拟退火法

A Star not a Tree? Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 3272   Accepted: 1664 Description Luke wants to upgrade his home computer network from 10mbs to 100mbs. His existing network uses 10base2 (coaxial) cables that allow you

POJ 2420

模拟退火算法.昨天看了PPT,原来模拟退火算法涉及到马尔什么链,开始理解,它其实就是一个关于抽样的问题.随机抽样,选取足够多的样本,然后逐步逼近.而在平面上,由于T的下降,使得逐渐缩小至一点.然后,就可以了. 算法: 在平面上随机选取一些点,当然这些点应当有一点相关的性吧.我猜的. 然后在这些点随机移动,若移动后更优,则移动,否则,留待下一次循环. #include <iostream> #include <cstdio> #include <cstring> #inc

三分 POJ 2420 A Star not a Tree?

题目传送门 1 /* 2 题意:求费马点 3 三分:对x轴和y轴求极值,使到每个点的距离和最小 4 */ 5 #include <cstdio> 6 #include <algorithm> 7 #include <cstring> 8 #include <cmath> 9 10 const int MAXN = 1e2 + 10; 11 const int INF = 0x3f3f3f3f; 12 double x[MAXN], y[MAXN]; 13 i

poj 3903 &amp; poj 2533 最长上升子序列(LIS)

最长上升子序列. 做这道题之前先做了2533,再看这道题,感觉两道题就一模一样,于是用2533的代码直接交, TLE了: 回头一看,数据范围.2533 N:0~1000:3903 N :1~100000. 原因终归于算法时间复杂度. 也借这道题学习了nlgn的最长上升子序列.(学习链接:http://blog.csdn.net/dangwenliang/article/details/5728363) 下面简单介绍n^2 和 nlgn 的两种算法. n^2: 主要思想:DP: 假设A1,A2..

半平面交 模板 poj 3335 poj 3130 poj 1474 判断半平面交是否为空集

半平面交模板 const double pi= acos(-1.0); #define arc(x) (x / 180 * pi) const double EPS = 1e-8; const int Max_N = 105; struct Point{ double x,y; Point(){} Point(double x, double y):x(x),y(y){} Point operator - (Point p){ return Point(x- p.x , y - p.y ) ;

POJ 3670 &amp;&amp; POJ 3671 (dp)

最长不下降子序列的应用嘛.两题都是一样的. POJ 3670:求给定序列按递增或递减排列时,所需改变的最小的数字的数目. POJ 3671:求给定序列按递增排列时,所需改变的最小的数字的数目. 思路就是求最长不下降子序列,然后剩下的就是需要改变的字母. 最长不下降子序列:(我之前有写过,不懂请戳)http://blog.csdn.net/darwin_/article/details/38360997 POJ 3670: #include<cstdio> #include<cstring

poj 3090 &amp;&amp; poj 2478(法雷级数,欧拉函数)

http://poj.org/problem?id=3090 法雷级数 法雷级数的递推公式很简单:f[1] = 2; f[i] = f[i-1]+phi[i]. 该题是法雷级数的变形吧,答案是2*f[i]-1. #include <stdio.h> #include <iostream> #include <map> #include <set> #include <stack> #include <vector> #include

二分图匹配 最大匹配数+最大点覆盖 POJ 1469+POJ 3041

最大匹配数就等于最大点覆盖,因为在图里面,凡是要覆盖的点必定是连通的,而最大匹配之后,若还有点没有覆盖到,则必定有新的匹配,与最大匹配数矛盾,如果去掉一些匹配,则必定有点没有覆盖到. POJ 1469 比较简单,用的经典的二分图匹配算法. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46