zoukankan      html  css  js  c++  java
  • bzoj2428 [HAOI2006]均分数据 模拟退火

    [HAOI2006]均分数据

    Time Limit: 5 Sec  Memory Limit: 128 MB
    Submit: 3434  Solved: 1091
    [Submit][Status][Discuss]

    Description

    已知N个正整数:A1、A2、……、An 。今要将它们分成M组,使得各组数据的数值和最平均,即各组的均方差最小。均方差公式如下:

    ,其中σ为均方差,是各组数据和的平均值,xi为第i组数据的数值和。

    Input

    第一行是两个整数,表示N,M的值(N是整数个数,M是要分成的组数)
    第二行有N个整数,表示A1、A2、……、An。整数的范围是1--50。
    (同一行的整数间用空格分开)

    Output

    这一行只包含一个数,表示最小均方差的值(保留小数点后两位数字)。

    Sample Input

    6 3
    1 2 3 4 5 6

    Sample Output

    0.00

    HINT

    对于全部的数据,保证有K<=N <= 20,2<=K<=6

    Source

    [Submit][Status][Discuss]


    HOME Back

    以前也没怎么写过模拟退火,这道题让我知道了一些怎么写

    退了10000次火,模拟退火主要靠感觉的吧,

    写法也是相当奇怪的

    当温度很高的时候,将随机出来的一个数,放入当前组里最小的一组,

    当温度比较低的时候,就随机放在一组里,然后判断交换后答案是否更优,是的话就交换,不然随机交换。

     1 #include<cstring>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<iostream>
     5 #include<cmath>
     6 
     7 #define N 10007
     8 #define ll long long
     9 using namespace std;
    10 inline int read()
    11 {
    12     int x=0,f=1;char ch=getchar();
    13     while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    14     while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    15     return x*f;
    16 }
    17 
    18 int n,m;
    19 int sum[N],a[N],belong[N];
    20 double minans=1e30,ave;
    21 
    22 void SA()
    23 {
    24     memset(sum,0,sizeof(sum));
    25     for (int i=1;i<=n;i++)
    26     {
    27         belong[i]=rand()%m+1;
    28         sum[belong[i]]+=a[i];
    29     }
    30     double ans=0;
    31     for (int i=1;i<=m;i++)
    32         ans+=(sum[i]-ave)*(sum[i]-ave);
    33     double T=10000;
    34     while(T>0.1)
    35     {
    36         T*=0.9;
    37         int t=rand()%n+1,x=belong[t],y;
    38         if (T>500) y=min_element(sum+1,sum+m+1)-sum;
    39         else y=rand()%m+1;
    40         if (x==y) continue;
    41         double tmp=ans;
    42         ans-=(sum[x]-ave)*(sum[x]-ave);
    43         ans-=(sum[y]-ave)*(sum[y]-ave);
    44         sum[x]-=a[t],sum[y]+=a[t];
    45         ans+=(sum[x]-ave)*(sum[x]-ave);
    46         ans+=(sum[y]-ave)*(sum[y]-ave);
    47         if (ans<=tmp) belong[t]=y;
    48         else if (rand()%10000>T) sum[x]+=a[t],sum[y]-=a[t],ans=tmp;
    49         else belong[t]=y;
    50     }
    51     if (ans<minans) minans=ans;
    52 }
    53 int main()
    54 {
    55     srand(19260817);
    56     n=read(),m=read();
    57     for (int i=1;i<=n;i++)
    58         a[i]=read(),ave+=a[i];
    59     ave/=(double)m;
    60     for (int i=1;i<=10000;i++) SA();
    61     printf("%.2lf
    ",sqrt(minans/m));
    62 }
  • 相关阅读:
    结对编程项目---四则运算
    作业三(代码规范、代码复审、PSP)
    作业2(源程序管理软件与项目管理软件)
    学习总结
    作业1
    寒假超市实习
    《软件工程》课程总结
    结对编程项目---四则运算
    作业三: 代码规范、代码复审、PSP
    作业二(2)目前流行的源程序版本管理软件和项目管理软件都有哪些,各有什么优缺点?
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8746060.html
Copyright © 2011-2022 走看看