zoukankan      html  css  js  c++  java
  • 随 机 贪 心

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

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

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

    不要以为随机到正解几率很小,假设随机到正解的概率为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));
    }
    
  • 相关阅读:
    改造我们的学习:有钱不会花,抱着金库抓瞎
    (转)我奋斗了18年才和你坐在一起喝咖啡
    初学者要知道的十件事
    [转]C#图像处理 (各种旋转、改变大小、柔化、锐化、雾化、底片、浮雕、黑白、滤镜效果)
    C#调用系统的复制、移动、删除文件对话框
    SQLite数据类型
    jquery禁用dropdownlist中某一项
    C# winform无标题窗体随意移动
    注册.NET Framework
    jQuery同步/异步调用后台方法
  • 原文地址:https://www.cnblogs.com/shikeyu/p/13274014.html
Copyright © 2011-2022 走看看