HDU 3732 Ahui Writes Word(多重背包)

http://acm.hdu.edu.cn/showproblem.php?pid=3732

题意:

初始有N个物品, 每个物品有cost[i]花费和val[i]价值, 你有m元钱, 现在问你最多能买多少总价值的物品?

其中N<=10W, m<=1W. 且cost[i]和val[i]都在[0,10]范围.

分析:

本题初看直接用01背包来做是直观的想法. 但是考虑到01背包的复杂度为O(N*m), 这么大的复杂度肯定不行.

然后我们发现其实每种物品只与它的cost[i]和val[i]有关, 如果某两个物品的cost[i]和val[i]完全相等, 我们可以把这两种物品合并(看出一种物品但是数量叠加), 最终我们直接解决一个多重背包问题即可. 如果是多重背包问题,
复杂度为O(m*sum( log(num[i]) ) )  其中 num[i]的和为N.

初始我们读取输入, 然后我们把所有的物品排序,然后在分类之后就构成了n种物品, 每种物品具有num[i]个的多重背包问题.

令dp[i][j]==x 表示购买前i种物品时总花费<=j时, 可以获得的最大价值为x.

初始化: dp全为0.

对于第i种商品, 有下面两种情况:

如果val[i]*num[i]>=m, 就做一次完全背包.

如果val[i]*num[i]<m, 就把第i种物品重新分类, 并做k+1次01背包.

最终所求: dp[n][m]的值.

程序实现, 用的滚动数组逆向递推, 所以dp只有[j]一维.

AC代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=121+5;

int n;//合并之后n种物品
int m;//最大花费值
int val[maxn]; //新分类i物品价值
int num[maxn]; //新分类i物品数目
int cost[maxn];//新分类i物品花费
int dp[10000+5];

//1次01背包过程
void ZERO_ONE_PACK(int cost,int val)
{
    for(int i=m;i>=cost;i--)
        dp[i] = max(dp[i], dp[i-cost]+val);
}

//1次完全背包过程
void COMPLETE_PACK(int cost,int val)
{
    for(int i=cost;i<=m;i++)
        dp[i] = max(dp[i], dp[i-cost]+val);
}

//1次多重背包过程
void MULTIPLY_PACK(int cost,int val,int sum)
{
    if(cost*sum>=m)
    {
        COMPLETE_PACK(cost,val);
        return ;
    }

    int k=1;
    while(k<sum)
    {
        ZERO_ONE_PACK(cost*k,val*k);
        sum-=k;
        k*=2;
    }
    ZERO_ONE_PACK(cost*sum, val*sum);
}

//Node用于保存原始输入的每个单词属性
struct Node
{
    int v,c;
    bool operator<(const Node &rhs)const
    {
        return v<rhs.v || (v==rhs.v && c<rhs.c);
    }
    bool operator==(const Node &rhs)const
    {
        return v==rhs.v && c==rhs.c;
    }
}nodes[100000+5];
int N;//原始N个单词

int main()
{
    while(scanf("%d%d",&N,&m)==2)
    {
        //读取输入
        for(int i=1;i<=N;i++)
        {
            char str[20];
            scanf("%s %d%d",str,&nodes[i].v,&nodes[i].c);
        }

        //将原始输入物品合并再分类
        sort(nodes+1,nodes+N+1);
        n=1;
        val[n]=nodes[1].v;
        cost[n]=nodes[1].c;
        num[n]=1;
        for(int i=2;i<=N;i++)
        {
            if(nodes[i]==nodes[i-1])
                num[n]++;
            else
            {
                n++;
                val[n]=nodes[i].v;
                cost[n]=nodes[i].c;
                num[n]=1;
            }
        }

        //递推输出
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++)
            MULTIPLY_PACK(cost[i],val[i],num[i]);
        printf("%d\n",dp[m]);
    }
    return 0;
}
时间: 2025-01-17 04:55:42

HDU 3732 Ahui Writes Word(多重背包)的相关文章

HDU 3732 Ahui Writes Word

乍一看是01背包,但是100000*10000的复杂度肯定是TLE的,但是(0 ≤ Vi , Ci ≤ 10),所以最多也只有100种物品,转化成多重背包去做. #include<cstdio> #include<cstring> #include<cmath> int N,C,vv,cc; int g[15][15]; char s[100]; int w[105],c[105],n1[105]; int tot; int f[10000+10]; int max(i

【HDOJ】3732 Ahui Writes Word

初看01背包,果断TLE.是因为n和C都比较大.但是vi和ci却很小,转化为多重背包. 1 #include <cstdio> 2 #include <cstring> 3 4 int map[15][15]; 5 int dp[10005]; 6 int n, C; 7 8 int max(int a, int b) { 9 return a>b ? a:b; 10 } 11 12 void ZeroOnePack(int v, int c) { 13 for (int i

【背包专题】F - Ahui Writes Word hdu3732【01背包+二进制优化】

We all know that English is very important, so Ahui strive for this in order to learn more English words. To know that word has its value and complexity of writing (the length of each word does not exceed 10 by only lowercase letters), Ahui wrote the

HDU 2159 FATE (二维多重背包)

FATE Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 9352    Accepted Submission(s): 4413 Problem Description 最近xhd正在玩一款叫做FATE的游戏,为了得到极品装备,xhd在不停的杀怪做任务.久而久之xhd开始对杀怪产生的厌恶感,但又不得不通过杀怪来升完这最后一级.现在的问

HDU 2082 找单词 (多重背包)

题意:假设有x1个字母A, x2个字母B,..... x26个字母Z,同时假设字母A的价值为1,字母B的价值为2,..... 字母Z的价值为26.那么,对于给定的字母,可以找到多少价值<=50的单词呢?单词的价值就是组成一个单词的所有字母的价值之和,比如,单词ACM的价值是1+3+14=18,单词HDU的价值是8+4+21=33.(组成的单词与排列顺序无关,比如ACM与CMA认为是同一个单词). 题解:把26个字母看做26种背包,有个数有价值,求价值不超过50的所有可能个数,就是标准的多重背包.

HDU #2191 买米问题 多重背包及其优化

Description 问题描述以及测试样例在这:HDU#2191 思路 这道题其实就是多重背包问题,即有 N 种物品和一个容量为 V 的背包,第 i 种物品最多有 n[i] 件可用,每件费用是 c[i] ,价值是 w[i] ,求哪些物品装入背包可以使得这些物品的费用总和不超过背包容量,且价值总和最大.在这道题中,背包容量是经费,费用是每种米的价格,价值是每种米的重量,求用给定的经费买米,使得买到米的总重量最大,注意经费是可以剩余的. 其实多重背包问题和完全背包问题非常相似,只不过前者的物品是有

HDU 2844 二进制优化的多重背包

Coins Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 11596    Accepted Submission(s): 4634 Problem Description Whuacmers use coins.They have coins of value A1,A2,A3...An Silverland dollar. One

HDU 2191 悼念512【多重背包+二进制优化】

大意分析: 多重背包,转化为01背包即可 可以用二进制进行优化 代码:(代码没有优化,下题是优化才可过的) 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 const int maxn = 105; 7 8 int n, m, tot; 9 int p[2005], h[2005]; 10 int dp[maxn]; 11 int solv

ACM学习历程—HDU 1059 Dividing(dp &amp;&amp; 多重背包)

Description Marsha and Bill own a collection of marbles. They want to split the collection among themselves so that both receive an equal share of the marbles. This would be easy if all the marbles had the same value, because then they could just spl