好久没写博客了,写个模拟退火水一水
思想
模拟退火的思想是基于显示中的退火,当能量逐步减小时,最后的状态将趋于稳定态。
一般的模拟退火有t t t (温度参数),d e l t a delta d e l t a (降温系数),b e g beg b e g (起始温度)和e n d end e n d (终止温度)四个变量,其中降温系数对答案的影响比较显著。
下面是温度慢慢降低时的一幅比较直观的图
实现
每次随机变换状态,然后比当前答案优的直接接受这个状态,否则有一个极小的概率接受这个状态,这个小概率事件可以帮助我们跳出局部最优解。
这个小概率f f f 为
f = { 1 , 比之前状态更优时 e x p ( Δ a n s / t ) , 状态不优时 f=\begin{cases}1,\text{比之前状态更优时}
\\exp(\Delta ans/t),\text{状态不优时}
\end{cases}
f = { 1 , 比之前状态更优时 e x p ( Δ a n s / t ) , 状态不优时
大概的代码实现可以看下面的例题.
例题
[SCOI2008]城堡
题目背景
2008NOI四川省选
题目描述
在一个国家里,有 n n n 个城市(编号为 0 0 0 到 n − 1 n-1 n − 1 )。这些城市之间有 n n n 条双向道路相连(编号为 0 0 0 到 n − 1 n-1 n − 1 ),其中编号为 i i i 的道路连接了城市 i i i 和城市 r i r_i r i (一条道路可以连接一个城市和它自身),长度为 d i d_i d i 。n n n 个城市中有 m m m 个拥有自己城堡,可以抵御敌人侵略。如果没有城堡的城市遭受攻击,则离它最近的城堡将派兵前往救援。
你的任务是在不超过 k k k 个没有城堡的城市中建立城堡,使得所有城市中“离最近城堡的距离”的最大值尽量小。换句话说,若令 d i s t ( c ) dist(c) d i s t ( c ) 表示城市 c c c 的最近城堡离它的距离,则你的任务是让 max { d i s t ( c ) } \max\{dist(c)\} max { d i s t ( c ) } 尽量小。
输入数据保证存在方案使得对于每个城市,至少有一个城堡能够到达。
输入格式
输入第一行为三个正整数 n , m , k n, m, k n , m , k 。第二行包含 n n n 个整数 r 0 , r 1 , … , r n − 1 r_0,r_1,\ldots,r_{n-1} r 0 , r 1 , … , r n − 1 。第三行包含 n n n 个整数 d 0 , d 1 , … , d n − 1 d_0,d_1,\ldots,d_{n-1} d 0 , d 1 , … , d n − 1 。第四行包含 m m m 个各不相同的 0 0 0 到 n − 1 n-1 n − 1 之间的整数,分别为 m m m 个城堡所在的城市编号。
输出格式
输出仅一行,包含一个整数,即 max { d i s t ( c ) } \max\{dist(c)\} max { d i s t ( c ) } 的最小值。
样例
样例输入
1 2 3 5 0 1 1 2 3 4 0 1 1 1 1 1
样例输出
提示
100 % 100\% 1 0 0 % 的数据满足: 2 ≤ n ≤ 50 2\leq n\leq 50 2 ≤ n ≤ 5 0 ,1 ≤ d i ≤ 1 0 6 1\leq d_i\leq 10^6 1 ≤ d i ≤ 1 0 6 ,0 ≤ m ≤ n − k 0\leq m\leq n-k 0 ≤ m ≤ n − k 。
题解
考虑模拟退火,随机一个序列,然后取前k个序列中的地块建城堡,然后计算答案,模拟退火即可。
代码实现
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 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 #include <iostream> #include <array> #include <algorithm> #include <cmath> #include <vector> #include <queue> #include <bitset> using namespace std;using gg=long long ;array<gg,110> nxt,to,val; array<gg,51> r,d,dep,head; bitset<51> alr; vector<gg> cb,cs; queue<gg> list; gg n,m,k,cnt=0 ,ans; void add (const gg &fr,const gg &t,const gg &v) { cnt++; nxt[cnt]=head[fr]; head[fr]=cnt; to[cnt]=t; val[cnt]=v; return ; } gg check () { gg tmp=0 ; for (gg i=0 ;i<n;i++) dep[i]=1145141919810 ; alr=0 ; for (gg i=0 ;i<cb.size ();i++){ dep[cb[i]]=0 ; list.push (cb[i]); alr[cb[i]]=1 ; } for (gg i=0 ;i<k;i++){ dep[cs[i]]=0 ; list.push (cs[i]); alr[cs[i]]=1 ; } while (list.size ()){ gg p=list.front (); list.pop (); alr[p]=0 ; for (gg i=head[p];i;i=nxt[i]){ if (dep[to[i]]>dep[p]+val[i]){ dep[to[i]]=dep[p]+val[i]; if (!alr[to[i]]){ list.push (to[i]); alr[to[i]]=1 ; } } } } for (gg i=k;i<cs.size ();i++) tmp=max (tmp,dep[cs[i]]); return tmp; } void sa () { for (double t=2000 ;t>=0.001 ;t*=0.998 ){ gg x=rand ()%k,y=rand ()%(n-m); swap (cs[x],cs[y]); gg tmp=check (),del=ans-tmp; if (del>0 ) ans=tmp; else if (exp (del/t)*RAND_MAX<=rand ()) swap (cs[x],cs[y]); } return ; } int main () { gg in; cin>>n>>m>>k; for (gg i=0 ;i<n;i++){ cin>>r[i]; } for (gg i=0 ;i<n;i++){ cin>>d[i]; } for (gg i=0 ;i<m;i++){ cin>>in; alr[in]=1 ; } for (gg i=0 ;i<n;i++){ if (alr[i]) cb.push_back (i); else cs.push_back (i); add (i,r[i],d[i]); add (r[i],i,d[i]); } ans=check (); for (gg i=1 ;i<=100 ;i++) sa (); cout<<ans<<'\n' ; return 0 ; }
其它例题
外太空旅行
【JSOI2016】炸弹攻击
【JSOI2004】 平衡点 / 吊打XXX