【模板】模拟退火 费马点以及最小球覆盖

最近学了一波模拟退火。个人感觉,就是随机算法,然后我们的目标点,一开始温度T高的时候会移动的剧烈,T小的时候移动的缓和(所以这就是为什么每一次移动的距离都是乘T)。然后真正的模拟退火是如果当前的tem比ans优,那就毫不犹豫地接受,否则则以一定概率接受。也就是那个exp(dE/T)> rand 那个。

然后还有爬山算法,就是只会一直找更优解,不接受差解,具体就是在模拟退火基础上,一直找最优解,找不到就降温(所以会陷入局部最优解的坑)。在网上嫖了一份代码(https://blog.csdn.net/just_sort/article/details/51648958)

 1 while(t>eps)
 2     {
 3         bool fuck = 1;
 4         while(fuck)
 5         {
 6             fuck = 0;
 7             for(int i=0; i<4; i++)
 8             {
 9                 z.x = s.x+dir[i][0]*t;
10                 z.y = s.y+dir[i][1]*t;
11                 double tmp = getSum(p,n,z);
12                 if(ans>tmp)
13                 {
14                     ans = tmp;
15                     s   = z;
16                     fuck= 1;
17                 }
18             }
19         }
20         t*=delta;
21     }

求费马点:poj2420

题目链接:https://vjudge.net/problem/POJ-2420

一开始就以坐标平均点作为起始点,然后移动的时候虽然可以无脑的向四周移动,但是我们可以这样看,求出每一个点和当前点的dx,dy,然后肯定是当前点朝dx和dy方向移动。这样会更好

(这个是带上一定概率接受更差解的)

 1 #include<iostream>
 2 #include<cmath>
 3 #include<cstdio>
 4 #include<ctime>
 5 #include<algorithm>
 6 using namespace std;
 7 #define eps 1e-6
 8 int n;
 9 const int N = 109;
10 struct Point{
11     double x,y;
12 }p[N],now;
13 double dis(Point a,Point b){
14     return sqrt( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y - b.y));
15 }
16 double getsum(Point u){
17     double res = 0;
18     for(int i = 1;i<=n;++i){
19         res += dis(p[i],u);
20     }
21     return res;
22 }
23 int main(){
24     scanf("%d",&n);
25     for(int i = 1;i<=n;++i){
26         scanf("%lf %lf",&p[i].x,&p[i].y);
27         now.x += p[i].x;
28         now.y += p[i].y;
29     }
30     now.x /= n; now.y /= n;
31     double ans = getsum(now);
32     double T = 100;
33     srand(23333);
34     while(T > eps){
35         double dx = 0,dy = 0;
36         for(int i = 1;i<=n;++i){
37             dx += (p[i].x - now.x)/dis(now,p[i]);
38             dy += (p[i].y - now.y)/dis(now,p[i]);
39         }
40         Point next = (Point){now.x + dx*T, now.y + dy*T};
41         double tem = getsum(next);
42         if(tem < ans){
43             ans = tem;
44             now = next;
45         }
46         else if(exp( (ans - tem) / T) > (rand()%10000)/10000.0){
47             ans = tem;
48             now = next;
49         }
50         T *= 0.98;
51     }
52     printf("%.0f",ans);
53     return 0;
54 }

最小球覆盖:poj2069

题目链接:https://vjudge.net/problem/POJ-2069

和上一题差不多,先以平均点做起始点,然后每次移动肯定是往距离当前点的最远点移动。

(这个没有接受更差解了)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #define eps 1e-6
 5 using namespace std;
 6 const int N = 40;
 7 int n;
 8 struct Point{
 9     double x,y,z;
10 }p[N],now;
11 double dis(Point u,Point v){
12     return sqrt( (u.x-v.x)*(u.x-v.x) + (u.y-v.y)*(u.y-v.y) + (u.z - v.z)*(u.z - v.z));
13 }
14 int main(){
15     while(~scanf("%d",&n) && n){
16         for(int i = 1 ; i <= n ;++i){
17             scanf("%lf %lf %lf",&p[i].x,&p[i].y,&p[i].z);
18             now.x+=p[i].x; now.y+=p[i].y; now.z += p[i].z;
19         }
20         now.x/=n; now.y/=n; now.z/=n;
21         double T = 100;
22         double ans = 1e99;
23         while(T > eps){
24             int k = 1;
25             for(int i = 1;i <= n ;++i){
26                 if(dis(now,p[i]) > dis(now,p[k]) ){
27                     k = i;
28                 }
29             }
30             double tem = dis(p[k],now);
31             ans = min(ans,tem);
32             now.x += ( (p[k].x - now.x)/tem )*T;
33             now.y += ( (p[k].y - now.y)/tem )*T;
34             now.z += ( (p[k].z - now.z)/tem )*T;
35             T *= 0.98;
36         }
37         printf("%.6f\n",ans);
38     }
39     return 0;
40 }

至于最小园覆盖,模拟退火的话和最小求覆盖一样啦。不过最小圆覆盖有线性的点增量法(下一篇讲到),所以就不妨在这里了。

原文地址:https://www.cnblogs.com/xiaobuxie/p/11619652.html

时间: 2024-08-02 17:33:13

【模板】模拟退火 费马点以及最小球覆盖的相关文章

poj 2420,模拟退火算法,费马点

题目链接:http://poj.org/problem?id=2420 题意:给n个点,找出一个点,使这个点到其他所有点的距离之和最小,也就是求费马点. 参考链接:http://www.cnblogs.com/heaad/archive/2010/12/20/1911614.html 这一篇文章写的很好,我这个小白都有一点小明白了. 记一下笔记: 模拟退火: 就是在一定范围内接受一些不是最优的解,来跳出局部最优,靠近整体最优. 贴一下伪代码: //#pragma comment(linker,

【数学基础】【欧拉定理模板】【费马小定理】

费马小定理:当p是一个质数时,且a和p互质,有ap-1=1(mod p) (欧拉定理的一种特殊情况) 欧拉定理:如果a和n互质,那么aφ(n)=1(mod n) 对于任意a,b,n就有 ab=aφ(n)+b mod φ(n)(mod n) 处理b数值较大的情况 ,采用分治思想,复杂度为O(logn) int mod = n; int fastpow(int a,int b) { long long ret = 1; tmp = a; while(b) { if(b&1) ret = ret*tm

hdu 4704 Sum (整数和分解+快速幂+费马小定理降幂)

题意: 给n(1<n<),求(s1+s2+s3+...+sn)mod(1e9+7).其中si表示n由i个数相加而成的种数,如n=4,则s1=1,s2=3.                         (全题文末) 知识点: 整数n有种和分解方法. 费马小定理:p是质数,若p不能整除a,则 a^(p-1) ≡1(mod p).可利用费马小定理降素数幂. 当m为素数,(m必须是素数才能用费马小定理) a=2时.(a=2只是题中条件,a可以为其他值) mod m =  *      //  k=

POJ 2420 A Star not a Tree? (计算几何-费马点)

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

poj 3990 Fermat Point in Quadrangle 凸包和费马点

题意: 求一个四边形的费马点. 分析: 模拟退火要么超时要么wa,这题的数据就是不想让随机算法过的..其实四边形的费马点很简单,如果是凸四边形的话费马点是对角线交点,如果是凹四边形费马点是凹点.但题目给的四个点顺序是不确定的,所以要先求下凸包. 代码: //poj 3990 //sep9 #include <iostream> #include <cmath> #include <algorithm> using namespace std; struct Point

CSU1516矩阵快速幂+费马小定理

通过这个题真的学到了不少东西,最起码矩阵快速幂算是入门了,普通快速幂也彻底明白了(以前都是打模板),了解了费马小定理 关键点 求(a^fib[b])%p 的值其中p是素数,0<a<p, b在int范围内 先假设fib[b]>p-1 那么上式 (a^fib[b])%p = (a^(p-1)*a^(p-1)*....*a^(p-1)*a^m)%p (这里 m = fib[b]%(p-1)) 由于p是素数且a<p那么gcd(a,p)=1,所以由费小可得(a^(p-1))%p=1 那上式就

HDU 4704 Sum(隔板原理+组合数求和公式+费马小定理+快速幂)

题目传送:http://acm.hdu.edu.cn/showproblem.php?pid=4704 Problem Description Sample Input 2 Sample Output 2 Hint 1. For N = 2, S(1) = S(2) = 1. 2. The input file consists of multiple test cases. 题意是输入一个N,求N被分成1个数的结果+被分成2个数的结果+...+被分成N个数的结果,N很大 1.隔板原理 1~N有

FZU - 1576【计算几何/费马点】

Oaiei居住在A城市,并且是这个城市建设的总设计师.最近有个问题一直困恼着他.A城市里有三个大型工厂,每个大型工厂每天都需要消耗大量的石油,现在城市里要建设一个石油中转站,从石油中转站到三个大型工厂都需要铺设石油管道.现在你的问题来了,应该如何建设这个石油中转站,使得石油中转站到三个大型工厂所需要铺设的石油管道线路最短,你能够帮助他吗? 设石油中转站B的坐标为(X,Y),三个大型工厂的坐标分别为C(X1,Y1),D(X2,Y2),E(X3,Y3),所输要铺设的石油管道线路总长为distance

hdu 4704 Sum (整数和分解+高速幂+费马小定理降幂)

题意: 给n(1<n<),求(s1+s2+s3+...+sn)mod(1e9+7). 当中si表示n由i个数相加而成的种数,如n=4,则s1=1,s2=3.                         (全题文末) 知识点: 整数n有种和分解方法. 费马小定理:p是质数,若p不能整除a.则 a^(p-1) ≡1(mod p). 可利用费马小定理降素数幂. 当m为素数,(m必须是素数才干用费马小定理) a=2时.(a=2仅仅是题中条件,a能够为其它值) mod m =   *      //