zoukankan      html  css  js  c++  java
  • Cookies

    Cookies

    有m块饼干,全部分给n个孩子,第i个孩子有个贪婪度(g_i),如果有(a_i)个孩子比第i个孩子的饼干多,则增加(a_i imes g_i)的怒气值,要求每个孩子至少分到一块饼干,现在寻找一种方案使总怒气值最低,(1≤N≤30, N≤M≤5000)

    首先贪心可知道,在一种最优的方案中,如果存在一对孩子,一个贪婪度低,分的饼干多,一个贪婪度高,分的饼干少,于是交换这两者分的饼干,必然结果会更加优秀,于是最优方案随贪婪度的递增,分的饼干递增。

    让孩子按照贪婪度从小到大排序,于是我们得设我们现在处理到哪一个孩子,还有总共已经分了多少块饼干,为了保证递减性,我们还得维护这个孩子分了几块饼干,显然会超时,于是显然不能表现该孩子分了几块饼干。

    但注意到一个孩子可以分多块饼干,类似完全背包,而我们只在乎相对大小关系,可以考虑阶段内转移优化,而孩子分的饼干的一种方案,饼干数都会有共同的相等的部分,也就是减去不改变怒气值,只改变了总饼干数。

    于是可以这样考虑,忽略上面所说的第三维,现在把g数组变为前缀和,设(f[i][j])表示处理到第i个孩子,已经分走了j块饼干的最小怒气值,如果当前孩子只分一块饼干,我只要枚举前面有多少人分的饼干数与之相同,否则只要把每个人的饼干数减掉i不影响怒气值,于是有

    [f[i][j]=max(f[i][j-i],max_{k=0}^{i-1}(f[k][j-(i-k)]+g[i]-g[k])) ]

    边界:(f[0][0]=0),其余无限大

    答案:(f[n][m])

    参考代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <functional>
    #include <algorithm>
    #define il inline
    #define ri register
    #define ll long long
    using namespace std;
    struct DATA{
        ll g;int id;
    }d[31];
    ll g[31],dp[31][5001];
    int ans[31],pre[31][5001];
    il bool comp(const DATA &a,const DATA &b){
        return a.g>b.g;
    }
    int main(){
        int n,m,i,j,k;
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;++i)
            scanf("%lld",&d[i].g),d[i].id=i;
        sort(d+1,d+n+1,comp);
        for(i=1;i<=n;++i)g[i]=d[i].g+g[i-1];
        memset(dp,1,sizeof(dp)),dp[0][0]=0;
        for(i=1;i<=n;++i)
            for(j=i;j<=m;++j){
                dp[i][j]=dp[i][j-i],pre[i][j]=i;
                for(k=0;k<i;++k)
                    if(dp[i][j]>dp[k][j-(i-k)]+(g[i]-g[k])*k)
                        dp[i][j]=dp[k][j-(i-k)]+(g[i]-g[k])*k,
                            pre[i][j]=k;
            }
        printf("%lld
    ",dp[n][m]);
        i=n,j=m;
        do{
            if(pre[i][j]==i){
                for(k=1;k<=i;++k)++ans[d[k].id];
                j-=i;
            }
            else{
                for(k=pre[i][j]+1;k<=i;++k)
                    ++ans[d[k].id];k=pre[i][j];
                j-=(i-k),i=k;
            }
        }while(i);
        for(i=1;i<=n;++i)printf("%d ",ans[i]);
        return 0;
    }
    
  • 相关阅读:
    Python学习-类的继承
    Python学习-else循环子句
    Python学习-类的基本知识
    Python学习-字符编码的理解
    Python小程序—修改haproxy配置文件
    Python学习-局部变量和全局变量以及递归
    蒙特卡洛积分法(三)
    蒙特卡洛积分法(二)
    蒙特卡洛积分法(一)
    由normal生成局部坐标系
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/10910882.html
Copyright © 2011-2022 走看看