• CH5105 Cookies (线性dp)


    传送门

    解题思路:

      贪心的想,贪婪值越大的孩子应该分得更多的饼干,那么先sort一遍在此基础上进行dp。最直观的方向,可以设dp[i][j]为前i个孩子一共分得j块饼干的怨恨最小值。然后转移第i+1个孩子的状态,设a[i]为比第i个孩子拿到更多饼干的孩子的个数,这时会出现两种情况:

      1.第i+1个孩子获得的饼干比第i个孩子少,那么a[i+1]=i

      2.第i+1个孩子获得了跟第i个孩子一样多的饼干,那么我们还要找i前面有多少个和i获得同样多的饼干的孩子个数,然后再求出a[i+1]

    显而易见第二种情况会大大增加时间复杂度,那么先画个图找找出路

     

    从图上的红框可以看出所有的孩子每人删掉同样多的饼干结果不变。那么获得一条状态转移:dp[i][j]=min(dp[i][j],dp[i][j-i])

    同样从上一张图看,若第i个孩子得到了一块饼干,可以通过枚举他前面第k个孩子同样得到1个饼干,得到第二个的状态转移:

       dp[i][j]=min(dp[i][j],dp[k][j-(i-k)]+k*(i到i-k的贪婪值之和))

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=5e3+10;
    struct node
    {
        int a,id;
    }q[55];
    bool cmp(node a,node b)
    {
        return a.a>b.a;
    }
    long long dp[51][maxn];
    struct no
    {
        int i,j;
    }g[51][maxn];
    long long sum[51],ans[51],r;int n,m;
    void print(int i,int j)
    {
        if(i==0)    return;
        print(g[i][j].i,g[i][j].j);
        if(g[i][j].i==i)for(int h=1;h<=i;h++)ans[q[h].id]++;
        else for(int h=g[i][j].i+1;h<=i;h++)ans[q[h].id]=1;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)    scanf("%d",&q[i].a),q[i].id=i;
        memset(dp,0x3f,sizeof dp);
        dp[0][0]=0;
        sort(q+1,q+1+n,cmp);
        for(int i=1;i<=n;i++)    sum[i]=sum[i-1]+q[i].a;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(j-i>=0&&dp[i][j]>dp[i][j-i]){
                    dp[i][j]=dp[i][j-i];
                    g[i][j].i=i;g[i][j].j=j-i;
                }
                for(int k=0;k<i;k++){
                    if(j-(i-k)>=0&&dp[i][j]>dp[k][j-(i-k)]+1LL*k*(sum[i]-sum[k])){
                        dp[i][j]=dp[k][j-(i-k)]+k*(sum[i]-sum[k]);
                        g[i][j].i=k;g[i][j].j=j-(i-k);
                    }
                }
            }
        }
        cout<<dp[n][m]<<endl;
        print(n,m);
        for(int i=1;i<=n;i++)
            printf("%d%c",ans[i],i==n?'
    ':' ');
    }
    View Code

     

  • 相关阅读:
    操作 Java 数组的 12 个最佳方法
    详解 JavaScript 中 splice() 方法
    Java 读取 .properties 配置文件的几种方式
    表单中单选、多选、选择框值的获取及表单的序列化
    一个调出上下文菜单的实例
    跨浏览器的事件侦听器和事件对象
    动态加载js和css
    php语言实现的7种基本的排序方法
    CORS(跨源资源共享)实战
    ubuntu中LAMP环境搭建及ubuntu语言和输入法设置
  • 原文地址:https://www.cnblogs.com/r138155/p/12631425.html
Copyright © 2020-2023  润新知