• 随 机 贪 心


    随机化贪心,顾名思义,就是边随机边贪心

    这类算法适合解决动态规划类的题目

    思想:在贪心原则正确的情况下,随机执行足够多次,就是正解了(涉及到概率学 (玄学 逃:)) ,这里不深究)

    不要以为随机到正解几率很小,假设随机到正解的概率为0.1%,我们执行100000次贪心,每次取最优,得到正解的概率是100%

    也就是这种贪心也变成了某种意义上的正解

    这需要用到我们的random_shuffle函数 复杂度平均为O(n),给数组乱序,用法和sort类似

    例子:HAOI 2006 均分数据
    已知 n 个正整数 a1,a2...an 。今要将它们分成 m 组,使得各组数据的数值和最平均,即各组的均方差最小。均方差公式如下://感觉貌似有点错,我把我认为对的写上了

    [sigma=sqrt{sum_{i=1}^n (x_i-ar{x})^2 over n} ar{x}={sum_{i=1}^n x_i over m} ]

    [nsigma^2=sum_{i=1}^n (x_i-ar{x})^2 ]

    做法:摸你退火,随机贪心,显然摸你退火不太稳,我们就随机贪心吧
    对式子变形:(nsigma^2=sum_{i=1}^n(x_i^2-2x_iar x+ar x^2)=sum_{i=1}^nx_i^2-2sum_{i=1}^nx_iar x+sum_{i=1}^nar x^2)
    因为(-2ar xsum_{i=1}^nx_i+sum_{i=1}^nar x^2)为定值,可以推测当(sum_{i=1}^nx_i)为定值,每个x尽量接近,(sum_{i=1}^nx_i^2)最大
    于是我们可以将数组 random_shuffle 若干次,每次贪心的取值,使每个 x 尽量相等(例如你可以把新加进来的数,加给最小 x),循环个50000次,时间复杂度有点假qwq
    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,sum;
    int a[21],x[10];
    double ans=10000000.0,az;
    inline void calc(){
    	memset(x,0,sizeof(x)); //O(n)
    	for(int i=1;i<=n;i++){
    		int p=1;
    		for(int j=1;j<=m;j++)
    		if (x[j] < x[p]) p=j;
    		x[p] += a[i];
    	} 
    	double now=0;
    	for(int i=1;i<=m;i++) now += (x[i]-az)*(x[i]-az);
    	now /= (double)m;
    	if (now<ans) ans=now;
    }
    void init(){
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum+=a[i];
    	az = (double)sum / m;
    	for(int i=1;i<=500000;i++)
    	{
    		random_shuffle(a+1,a+n+1); //O(n);
    		calc();	
    	}
    }
    int main(){
    	init();
    	printf("%.2f",sqrt(ans));
    }
    
  • 相关阅读:
    delphi与JAVA的webservice架构
    process执行DOS命令
    DELPHI+JAVA 之间使用WebService
    一步一步用delphi实现webservice
    集合接口
    再次郑重声明
    京东的crm做的不错,赞一个
    vs 2010 ClickOnce 发布设置界面,系统必选包中缺少 fx2.0 的解决方法
    使用vs2010生成clickonce安装引导程序的方法
    用 Axialis IconWorkshop 将ico图标转换成gif图标
  • 原文地址:https://www.cnblogs.com/shikeyu/p/13274014.html
Copyright © 2020-2023  润新知