HDU 3732 Ahui Writes Word(01背包转化为多重背包)

Ahui Writes Word

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 2776    Accepted Submission(s): 988


Problem Description
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 complexity of the total is less than or equal to C.
Question: the maximum value Ahui can get.
Note: input words will not be the same.
 

Input
The first line of each test case are two integer N , C, representing the number of Ahui’s words and the total complexity of written words. (1 ≤ N ≤ 100000, 1 ≤ C ≤ 10000)
Each of the next N line are a string and two integer, representing the word, the value(Vi ) and the complexity(Ci ). (0 ≤ Vi , Ci ≤ 10)
 

Output
Output the maximum value in a single line for each test case.
 

Sample Input
    
    
    
    
5 20 go 5 8 think 3 7 big 7 4 read 2 6 write 3 5
 

Sample Output
    
    
    
    
15
Hint
Input data is huge,please use “scanf(“%s”,s)”
   

<pre name="code" class="cpp">#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<ctype.h>
#include<queue>
#include<vector>
#include<set>
#include<cstdio>
#include<cmath>
#define mem(a,x) memset(a,x,sizeof(a))
#define inf 1<<30
#define NN 10004
using namespace std;
const double PI = acos(-1.0);
typedef long long LL;
/**********************************************************************
N个单词,总复杂度V
输入单词,单词的复杂度ci,价值wi
求在总复杂度V范围内能获得的最大价值
01背包--然而超时了。。。
于是开始优化:
题目给了很特别的范围:0<=ci,wi<=10
仔细想想会发现,最多只能组成121(11*11)件物品,但是题目给了100000件
于是想到很多物品是重复的,换多重背包写
**********************************************************************/
int note[13][13];//note[i][j]表示体积i价值j的物品的数量
int f[NN];
int c[123],w[123],num[123];
int N,V;
void ZeroOnePack(int ci,int wi)
{
    for (int v = V; v >= ci; v--)
    {
        f[v] = max(f[v],f[v-ci]+wi);
    }
}
void CompletePack(int ci,int wi)
{
    for (int v = ci; v <= V; v++)
    {
        f[v] = max(f[v],f[v-ci]+wi);
    }
}
int main()
{
    while (cin>>N>>V)
    {
        mem(f,0);
        mem(note,0);
        char s[20];
        for (int i = 0,c,w; i < N; i++)
        {
            scanf("%s%d%d",s,&w,&c);
            note[c][w]++;
        }
        int n = 0;
        for (int i = 0; i <= 10; i++)
        {
            for (int j = 0; j <= 10; j++)
            {
                if (note[i][j] > 0)
                {
                    n++;
                    c[n] = i,w[n] = j,num[n] = note[i][j];
                }
            }
        }
//下面就是多重背包,多重背包开二维也是超时,于是上一维转化01、完全的做法
        for (int i = 1; i <= n; i++)
        {
            if (c[i]*num[i] >= V)
                CompletePack(c[i],w[i]);
            else
            {
                int k = 1,rest = num[i];
                while (k <= rest)
                {
                    ZeroOnePack(k*c[i],k*w[i]);
                    rest -= k;
                    k *= 2;//二进制拆分的方法
                }
                ZeroOnePack(rest*c[i],rest*w[i]);//剩下数量为rest
            }
        }
        printf("%d\n",f[V]);
    }
    return 0;
}

 
  


你可能感兴趣的:(算法,背包,杭电)