• Acwing-277-饼干(DP)


    链接:

    https://www.acwing.com/problem/content/279/

    题意:

    圣诞老人共有M个饼干,准备全部分给N个孩子。

    每个孩子有一个贪婪度,第 i 个孩子的贪婪度为 g[i]。

    如果有 a[i] 个孩子拿到的饼干数比第 i 个孩子多,那么第 i 个孩子会产生 g[i]*a[i]的怨气。

    给定N、M和序列g,圣诞老人请你帮他安排一种分配方式,使得每个孩子至少分到一块饼干,并且所有孩子的怨气总和最小。

    思路:

    先考虑贪心,怨气较大的人得到的饼干肯定较多.
    可以先进行排序, 再去进行DP, 考虑Dp使没有确定的值.
    对于Dp[i,j]表示前i个孩子,共分配j个饼干的情况.
    对于第i个孩子, 考虑将其分配大于1个饼干,可以发现将前i个人的饼干数都减一,并不影响答案的数值.
    在考虑从i开始往前k个孩子全部分配1个饼干的情况,挨个查找.同时前缀和记录怨气的总值.
    而为了找到每个孩子的具体数值.可以用a,b两个数组记录某个状态是由那个状态转移而来.
    结束DP之后.递归查找.当某个状态是由孩子个数相同情况推出来的时候.可以将这些孩子的总数诶个加1.
    否则可以得到k+1到n这些孩子的饼干数都为1.
    其中还用到了神奇的排序...

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int INF = 1e9;
    
    int Dp[50][5010];
    int G[50];
    int Sum[50];
    int C[50];
    int a[50][5010], b[50][5010];
    int Ans[50];
    int n, m;
    
    bool cmp(int l, int r)
    {
        return G[l] > G[r];
    }
    
    void Ser(int n, int m)
    {
        if (n == 0)
            return;
        Ser(a[n][m], b[n][m]);
        if (a[n][m] == n)
        {
            for (int i = 1;i <= n;i++)
                Ans[C[i]]++;
        }
        else
        {
            for (int i = a[n][m]+1;i <= n;i++)
                Ans[C[i]] = 1;
        }
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        for (int i = 1;i <= n;i++)
            scanf("%d", &G[i]), C[i] = i;
        for (int i = 0;i <= n;i++)
        {
            for (int j = 0;j <= m;j++)
                Dp[i][j] = INF;
        }
        sort(C+1, C+1+n, cmp);
        Dp[0][0] = 0;
        for (int i = 1;i <= n;i++)
        {
            Sum[i] = Sum[i-1]+G[C[i]];
            for (int j = i;j <= m;j++)
            {
                Dp[i][j] = Dp[i][j-i];
                a[i][j] = i;
                b[i][j] = j-i;
                for (int k = 0;k < i;k++)
                {
                    if (Dp[i][j] > Dp[k][j-(i-k)]+k*(Sum[i]-Sum[k]))
                    {
                        Dp[i][j] = Dp[k][j-(i-k)]+k*(Sum[i]-Sum[k]);
                        a[i][j] = k;
                        b[i][j] = j-(i-k);
                    }
                }
            }
        }
        printf("%d
    ", Dp[n][m]);
        Ser(n, m);
        for (int i = 1;i <= n;i++)
            printf("%d ", Ans[i]);
        printf("
    ");
    
        return 0;
    }
    
  • 相关阅读:
    (转)ASP.NET-关于Container dataitem 与 eval方法介绍
    WinForm控件复杂数据绑定常用数据源(对Combobox,DataGridView等控件DataSource赋值的多种方法)
    转载 C# BindingSource
    repeater控件实现分页
    JS操作SELECT方法
    C#中的Invoke
    ios深拷贝,浅拷贝,拷贝自定义对象的简单介绍(转)
    IOS的一些尺寸
    ASP.NET多线程下使用HttpContext.Current
    一些xcode5.1创建的工程在xcode6.0下不能编译的问题
  • 原文地址:https://www.cnblogs.com/YDDDD/p/11494193.html
Copyright © 2020-2023  润新知