随机化学习笔记

以后不会正解就用这东西。

随机函数

说一个单独的数是「随机数」是无意义的,所以以下我们都默认讨论「随机数列」,即使提到「随机数」,指的也是「随机数列中的一个元素」。
现有的计算机的运算过程都是确定性的,因此,仅凭借算法来生成真正不可预测、不可重复的随机数列是不可能的。

实现

rand

rand函数可以实现一个伪随机数,头文件cstdlib。其会返回一个在区间 \([0,\)MAX\(]\) 的伪随机数,其中MAX是标准库的一个宏,在Linux操作系统下默认为 \(2^{31}-1\)
rand需要一个随机数种子,可以用srand(seed)来实现,其中seed是种子。
同一程序使用相同的seed两次运行,在同一机器、同一编译器下,随机出的结果将会是相同的。
有一个选择是使用当前系统时间来作为随机种子:srand(time(nullptr))

mt19937

类似于rand的随机数函数,头文件radom,种子mt19937 myrand(time(nullptr));,调用myrand()
还有很多随机函数,就不列举了。

真神-random_shuffle

猴子排序党狂喜。效果为随机打乱序列。头文件algorithm,种子同rand

警告:
random_shuffle\(C++14\) 起被弃用,\(C++17\) 起被移除。
在 C++11 以及更新的标准中,您可以使用shuffle 函数代替原来的 random_shuffle。使用方法为 shuffle(v.begin(), v.end(), rng)(最后一个参数传入的是使用的随机数生成器,一般情况使用以真随机数生成器random_device播种的梅森旋转伪随机数生成器 mt19937)。

随机化技巧

用随机元素命中目标集合

其实就是用随机集合来覆盖所有答案。有时候你不会求正解,就多随机几次,将随即出来的答案求出最优的就好了,一般随机 \(100\) 次,答案少一点或者时间复杂度高一点的话可以适当减少。

随机生成数据

这个都用过吧。

随机化用于哈希

对于每个元素随机赋值哈希值,你运气好的话可能会减少哈希冲突(((

随机化算法

爬山算法

采用启发式方法,每次在当前找到的最优解 \(x\) 附近找一个解 \(x'\),如果比当前解更优的话就移动过去,否则不动。对于单峰函数显然可行。
爬山算法一般会引入温度参数(类似模拟退火(下一章的))。类比地说,爬山算法就像是一只兔子喝醉了在山上跳,它每次都会朝着它所认为的更高的地方(这往往只是个不准确的趋势)跳,显然它有可能一次跳到山顶,也可能跳过头翻到对面去。不过没关系,兔子翻过去之后还会跳回来。显然这个过程很没有用,兔子永远都找不到出路,所以在这个过程中兔子冷静下来并在每次跳的时候更加谨慎,少跳一点,以到达合适的最优点。
降温温参数略小于 \(1\),一般在 \([0,985,0.999]\) 选取。
劣势:容易陷入局部最优解
例题:平衡点/吊打XXX

点击查看代码
void hillclimb(){
    double t = 1000;
    while(t>1e-8){
        double nowx = 0 , nowy = 0;
        for(int i=1;i<=n;++i){
            double dx = x[i] - ansx , dy = y[i] - ansy;
            double dis = sqrt(dx*dx+dy*dy);
            nowx += (x[i] - ansx) * w[i] / dis;
            nowy += (y[i] - ansy) * w[i] / dis;
        }
        ansx += nowx * t, ansy += nowy * t;
        if(t>0.5)t *= 0.5;
        else t *= 0.97;
    }
}
//注意这题需要特判只有一个点的情况

模拟退火

模拟退火是一种随机化算法。当一个问题的方案数量极大(甚至是无穷的)而且不是一个单峰函数时,我们常使用模拟退火求解。
注意到爬山算法只有可能移动到比当前的解更优的解上去,但是最优解可能先要找到一个比当前劣的解才能找到它。这就是模拟退火的思想:如果比当前解更有就选这个解,否则有一定概率接受。

posted @ 2025-10-04 14:23  虚空远行者  阅读(12)  评论(0)    收藏  举报