zoukankan      html  css  js  c++  java
  • B-happy card-基础DP

    题目链接:http://acm.csust.edu.cn/problem/3028

    Description

     

    给你n个人,每一个人最多可以选k张牌,这n个人都喜欢数s,一张牌有一个数,如果这个数是s,则这个牌称为happy card

    每一个人拿到不同数量的happy card 可以获得不同数量的欢乐值。

    假如一个人拿到了 张happy card ,则可以获得 hi 的欢乐值(hi数组单调递增), 没有happy card的人的欢乐值为0.

    如果没有拿到happy card,则获得的欢乐值为0。

    现在你需要把着n张牌分配给这n个人(每个人的牌数都可以为0),使这n个人的快乐值总和最大

    Input

     

    第一行三个数字1n500, 1kn , 1s1e9

    接下来n个数代表n张牌上的数ai, 1ai1e9

    接下来k个数代表hi的值,1hi1e9

    保证 hihi1

    Output

     

    最大的快乐值和

    Sample Input 1 

    5 3 2
    2 2 2 2 2
    2 6 7

    Sample Output 1

    14

    Sample Input 2 

    4 3 9
    9 9 9 9 
    1 2 3

    Sample Output 2

    4


    一个DP题,对于萌新来讲可以有的难度。

    列出所有条件:人数n,总的快乐牌num,限制手牌m

    我们可以DP的是:前i个人在总牌数为j的情况下,第i个人拿k张牌的最大幸福值。想想似乎和01背包有点儿类似,那么状态转移方程也就不难写出来了:

    dp[i][j]=max(dp[i-1][j-k]+h[k],dp[i][j]);当然我们的第一维其实可以直接滚动掉的。。

    其实算法还可以再进行时间的优化,将其化为n2算法。

    实际上人数是一个无用条件,我们知道总的快乐牌数,那么人数一定会大于等于这个数。这种情况的所有必要条件就是:总的快乐牌num,限制牌堆m,那么可以化成以下情景:知道总的牌数num,问在限制每堆最大牌数为m时,堆成几堆牌能够使得快乐值最大。其方程式为:

    dp[j]=max(dp[j],dp[j-i]+h[i]);请大家自行思考原因。

    以下是AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    #define ll long long
    
    const int mac=5e2+10;
    
    int h[mac];
    ll dp[mac][mac];
    
    int main()
    {
        int n,m,s;
        int num=0;
        scanf ("%d%d%d",&n,&m,&s);
        for (int i=1; i<=n; i++){
            int x;
            scanf ("%d",&x);
            if (x==s) num++;
        }
        for (int i=1; i<=m; i++){
            int x;
            scanf ("%d",&x);
            h[i]=x;
        }
        for (int i=1; i<=n; i++){
            for (int j=1; j<=num; j++){
                for (int k=1; k<=min(j,m); k++){//枚举第i个人取k张牌 
                    dp[i][j]=max(dp[i-1][j-k]+h[k],dp[i][j]);
                }
            }
        }
        printf ("%lld
    ",dp[n][num]);
        return 0;
    }
    View Code

    以下是滚动数组优化的AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    #define ll long long
    
    const int mac=500+10;
    
    int num=0,lim[mac];
    ll dp[mac];
    
    int main()
    {
        int n,m,s;
        scanf ("%d%d%d",&n,&m,&s);
        for (int i=1; i<=n; i++){
            int x;
            scanf ("%d",&x);
            if (x==s) ++num;
        }
        for (int i=1; i<=m; i++){
            int x;
            scanf ("%d",&x);
            lim[i]=x;
        }
        for (int i=1; i<=n; i++){
            for (int j=num; j>=1; j--){
                for (int k=1; k<=min(m,j); k++){
                    dp[j]=max(dp[j],dp[j-k]+lim[k]);
                }
            }
        }
        printf ("%lld
    ",dp[num]);
        return 0;
    }
    View Code

    以下是n2的AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    #define ll long long
    
    const int mac=500+10;
    
    int num=0,h[mac];
    ll dp[mac];
    
    int main()
    {
        int n,m,s;
        scanf ("%d%d%d",&n,&m,&s);
        for (int i=1; i<=n; i++){
            int x;
            scanf ("%d",&x);
            if (x==s) ++num;
        }
        for (int i=1; i<=m; i++){
            int x;
            scanf ("%d",&x);
            h[i]=x;
        }
        for (int i=1; i<=m; i++){
            for (int j=i; j<=num; j++){
                dp[j]=max(dp[j],dp[j-i]+h[i]);
            }
        }
        printf ("%lld
    ",dp[num]);
        return 0;    
    }
    View Code
    路漫漫兮
  • 相关阅读:
    Javascript 获得数组中相同或不同的数组元素   
    Java IO流 FileOutputStream、FileInputStream的用法   
    你的项目中使用过哪些JSTL标签?
    JavaWeb代码复用
    软件质量保证体系是什么
    二叉树的递归遍历框架:
    二叉树节点的定义框架:
    SQL 2012 Always On 为 MSCRMSqlClrLogin SQL 登录名创建非对称密钥时报语法错误
    linux命令指usermod(管理用户以及权限的命令)
    Dynamics CRM 2013 SP1 升级到Dynamics CRM 2015
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/12003688.html
Copyright © 2011-2022 走看看