OSDN Git Service

style: format markdown files with remark-lint
author24OI-bot <15963390+24OI-bot@users.noreply.github.com>
Sat, 27 Jul 2019 08:27:17 +0000 (04:27 -0400)
committer24OI-bot <15963390+24OI-bot@users.noreply.github.com>
Sat, 27 Jul 2019 08:27:17 +0000 (04:27 -0400)
docs/misc/hill-climbing.md

index 8b69a72..3e22cbe 100644 (file)
@@ -9,15 +9,14 @@
 这种算法对于单峰函数显然可行。
 
 > Q:你都知道是单峰函数了为什么不三分呢
-> A:在多年的OI生活中,我意识到了,人类是有极限的,无论多么工于心计,绞尽脑汁,状态总是表示不出来的,出题人的想法总是猜不透的,边界总是写不对的——所以——我不三分了JOJO!
+> A:在多年的 OI 生活中,我意识到了,人类是有极限的,无论多么工于心计,绞尽脑汁,状态总是表示不出来的,出题人的想法总是猜不透的,边界总是写不对的——所以——我不三分了 JOJO!
 
-认真地说,爬山算法的优势在于当正解的写法你并不了解(常见于毒瘤计算几何和毒瘤数学题),或者本身状态维度很多,无法容易地写分治(例2就可以用二分完成合法正解)时,可以通过非常暴力的计算得到最优解。
+认真地说,爬山算法的优势在于当正解的写法你并不了解(常见于毒瘤计算几何和毒瘤数学题),或者本身状态维度很多,无法容易地写分治(例 2 就可以用二分完成合法正解)时,可以通过非常暴力的计算得到最优解。
 
 但是对于多数需要求解的函数中,爬山算法很容易进入一个局部最优解,如下图(最优解为 $\color{green}{\Uparrow}$ ,而爬山算法可能找到的最优解为 $\color{red}{\Downarrow}$ )。
 
 ![](./images/hill-climbing.png)
 
-
 * * *
 
 ## 具体实现
 
 兔子清醒的过程就是降温过程,在爬山的时候会不断减小之。
 
-关于降温:一般而言降温参数设定在0.985-0.999,是略小于1的常数。
+关于降温:一般而言降温参数设定在 0.985-0.999,是略小于 1 的常数。
 
-# 例1 球形空间产生器
+# 例 1 球形空间产生器
 
-这里以一道(其实正解是高斯消元)的适合爬山的好题[LuoguP4035 [JSOI2008]球形空间产生器](https://www.luogu.org/problem/P4035)为例
+这里以一道(其实正解是高斯消元)的适合爬山的好题[LuoguP4035 \[JSOI2008\] 球形空间产生器](https://www.luogu.org/problem/P4035)为例
 
-题意:给出N维空间中的N个点,已知他们在一个N维球上,求出球心。n<=10,坐标绝对值不超过10000.
+题意:给出 N 维空间中的 N 个点,已知他们在一个 N 维球上,求出球心。n&lt;=10, 坐标绝对值不超过 10000.
 
 很明显的单峰函数,可以使用爬山结局。本题算法流程:
 
 
 2、对于当前的球心,求出每个已知点到这个球心欧氏距离的平均值。
 
-3、遍历所有已知点。记录一个改变值cans(分开每一维度记录)对于每一个点的欧氏距离,如果大于平均值,就把改变值加上差值,否则减去。实际上并不用判断这个大小问题,只要不考虑绝对值,直接用坐标计算即可。这个过程可以形象地转化成一个新的球心,在空间里推来推去,碰到太远的点就往点的方向拉一点,碰到太近的点就往点的反方向推一点。
+3、遍历所有已知点。记录一个改变值 cans(分开每一维度记录)对于每一个点的欧氏距离,如果大于平均值,就把改变值加上差值,否则减去。实际上并不用判断这个大小问题,只要不考虑绝对值,直接用坐标计算即可。这个过程可以形象地转化成一个新的球心,在空间里推来推去,碰到太远的点就往点的方向拉一点,碰到太近的点就往点的反方向推一点。
 
-4、将我们记录的cans乘上温度,更新球心,回到步骤2
+4、将我们记录的 cans 乘上温度,更新球心,回到步骤 2
 
 5、在温度非常小的时候结束。
 
-
 因此,我们在更新球心的时候,不能直接加上改变值,而是要乘上温度。
 
 并不是每一道爬山题都可以具体地用温度解决,这只是一个例子。
 
-
 代码如下:
-```
-#include <bits/stdc++.h>
-using namespace std;
-double ans[10001],cans[100001],dis[10001],tot,f[1001][1001],seed=718;
-int n;
-double check()
-{
-       tot=0;
-       for(int i=1;i<=n+1;i++)
-       {
-               dis[i]=0;cans[i]=0;
-               for(int j=1;j<=n;j++)
-                       dis[i]+=(f[i][j]-ans[j])*(f[i][j]-ans[j]);
-               dis[i]=sqrt(dis[i]);//欧氏距离
-               tot+=dis[i];
-       }
-       tot/=(n+1);//平均
-       for(int i=1;i<=n+1;i++)
-       for(int j=1;j<=n;j++)
-       cans[j]+=(dis[i]-tot)*(f[i][j]-ans[j])/tot;//对于每个维度把修改值更新掉,欧氏距离差*差值贡献
-}
-int main()
-{
-       srand(seed);
-       cin>>n;
-       for(int i=1;i<=n+1;i++)
-               for(int j=1;j<=n;j++)
-               {
-                       cin>>f[i][j];
-                       ans[j]+=f[i][j];
-               }
-       for(int i=1;i<=n;i++)ans[i]/=(n+1);//初始化
-       for(double t=10001;t>=0.0001;t*=0.9999)//不断降温
-       {
-               check();
-               for(int i=1;i<=n;i++)
-                       ans[i]+=cans[i]*t;//修改
-       }
-       for(int i=1;i<=n;i++)printf("%.3f ",ans[i]);
-       
-}
-```
+
+    #include <bits/stdc++.h>
+    using namespace std;
+    double ans[10001],cans[100001],dis[10001],tot,f[1001][1001],seed=718;
+    int n;
+    double check()
+    {
+       tot=0;
+       for(int i=1;i<=n+1;i++)
+       {
+               dis[i]=0;cans[i]=0;
+               for(int j=1;j<=n;j++)
+                       dis[i]+=(f[i][j]-ans[j])*(f[i][j]-ans[j]);
+               dis[i]=sqrt(dis[i]);//欧氏距离
+               tot+=dis[i];
+       }
+       tot/=(n+1);//平均
+       for(int i=1;i<=n+1;i++)
+       for(int j=1;j<=n;j++)
+       cans[j]+=(dis[i]-tot)*(f[i][j]-ans[j])/tot;//对于每个维度把修改值更新掉,欧氏距离差*差值贡献
+    }
+    int main()
+    {
+       srand(seed);
+       cin>>n;
+       for(int i=1;i<=n+1;i++)
+               for(int j=1;j<=n;j++)
+               {
+                       cin>>f[i][j];
+                       ans[j]+=f[i][j];
+               }
+       for(int i=1;i<=n;i++)ans[i]/=(n+1);//初始化
+       for(double t=10001;t>=0.0001;t*=0.9999)//不断降温
+       {
+               check();
+               for(int i=1;i<=n;i++)
+                       ans[i]+=cans[i]*t;//修改
+       }
+       for(int i=1;i<=n;i++)printf("%.3f ",ans[i]);
+       
+    }
 
 * * *
 
-# 例2 吊打XXX
+# 例 2 吊打 XXX
 
 此处代码以[「BZOJ 3680」吊打 XXX](https://www.lydsy.com/JudgeOnline/problem.php?id=3680)(求 $n$ 个点的带权类费马点)为例。