• [HAOI2006][BZOJ2428] 均分数据


    2428: [HAOI2006]均分数据

    Time Limit: 5 Sec  Memory Limit: 128 MB
    Submit: 801  Solved: 231
    [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

     
    第一次写模拟退火……常数设不好。试验了很多次。
    971708 ws_fqk 2428 Accepted 1284 kb 596 ms C++/Edit 1238 B 2015-05-13 10:47:32
    971707 ws_fqk 2428 Wrong_Answer 1284 kb 404 ms C++/Edit 1237 B 2015-05-13 10:47:10
    971705 ws_fqk 2428 Wrong_Answer 1284 kb 368 ms C++/Edit 1240 B 2015-05-13 10:45:39
    971704 ws_fqk 2428 Wrong_Answer 1284 kb 160 ms C++/Edit 1240 B 2015-05-13 10:45:21
    971703 ws_fqk 2428 Accepted 1284 kb 608 ms C++/Edit 1242 B 2015-05-13 10:44:59
    971701 ws_fqk 2428 Accepted 1284 kb 1172 ms C++/Edit 1243 B 2015-05-13 10:43:58

    最后调到了600ms。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    using namespace std;
    int n,m,k,pos[21],a[21];
    double ave,ans,mn=100000007,sum[21];
    void solve()
    {
        double t=10000; //初始温度
        ans=0;
        memset(sum,0,sizeof(sum));
        for (int i=1;i<=n;i++) pos[i]=rand()%m+1;
        for (int i=1;i<=n;i++) sum[pos[i]]+=a[i];
        for (int i=1;i<=m;i++) ans+=(sum[i]-ave)*(sum[i]-ave);
        while (t>0.1)
        {
            t*=0.91; //降温速率 0.9时WA。
    //-----------------------------------------------------------------------
    int t1=rand()%n+1,x=pos[t1],y; if (t>500) y=min_element(sum+1,sum+m+1)-sum; else y=rand()%m+1; //随机选取两个位置 为什么>500取最小我也很不解,求解释。
    //-----------------------------------------------------------------------
    if (x==y) continue; double pre=ans; ans-=(sum[x]-ave)*(sum[x]-ave); ans-=(sum[y]-ave)*(sum[y]-ave); sum[x]-=a[t1]; sum[y]+=a[t1]; ans+=(sum[x]-ave)*(sum[x]-ave); ans+=(sum[y]-ave)*(sum[y]-ave); //换位置,更新ans,sum。
    //-----------------------------------------------------------------------
    if (rand()%10000>t&&ans>pre) { sum[x]+=a[t1]; sum[y]-=a[t1]; ans=pre; } else pos[t1]=y; } //若不优,则返回原来的值,否则(小于概率或更优)更换位置。
    //-----------------------------------------------------------------------
    if (ans<mn) mn=ans; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) { scanf("%d",&a[i]); ave+=a[i]; } ave/=m; for (int i=1;i<=5000;i++) solve(); printf("%.2lf",sqrt(mn/m)); return 0; }
  • 相关阅读:
    codeforces 459 B.Pashmak and Flowers 解题报告
    poj 1789 Truck History 解题报告
    poj 1258 Agri-Net 解题报告
    poj 1860 Currency Exchange 解题报告
    poj 1094 Sorting It All Out 解题报告
    poj 3368 Frequent values 解题报告
    hdu 1548 A strange lift 解题报告
    BestCoder4 1002 Miaomiao's Geometry (hdu 4932) 解题报告
    hdu 1400 Mondriaan's Dream 解题报告
    打电话主要代码(意图用法)
  • 原文地址:https://www.cnblogs.com/ws-fqk/p/4499753.html
Copyright © 2020-2023  润新知