题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=3732
题目大意:阿辉要记单词,所有单词的长度都不超过10个字符,每个单词都有一定的价值跟复杂性,
知道每个单词的价值跟复杂性都写下来了,阿辉写单词的总的复杂度不能超过C,要你求阿辉可以得到
的最大价值。
解题思路:乍一看本题为一个简单0 1背包问题,但用0 1 背包做的时间复杂度为10^9在一秒中内不可能
完成,但细看题目后发现Vi和Ci都小于等于10也就是说价值和费用的种类总共只有一百种,只需要统计
所有价值、费用相同的数目及可以将问题转化为一个多重背包问题。
源码及注释:
#include<stdio.h>
#include<string.h>
int count[11][11]; //用于统计相同价值和费用的单词的数目
int dp[10005];
int max(int a,int b)//求a和b的最大值
{
return a > b ? a : b;
}
int main()
{
int n,i,j,v,ci,c;
char Str[15];
while(scanf("%d%d",&n,&c) != EOF)
{
memset(count,0,sizeof(count));//将所有种类的数目初始化为0
for(i = 0; i < n; i++)
{
scanf("%s%d%d",Str,&v,&ci);
count[v][ci]++; //统计价值为v费用为ci的单词的数目
}
memset(dp,0,sizeof(dp));
for(i = 0; i < 11; i++) //i代表价值
{
for(j = 0; j < 11; j++) //j代表费用
{
if(count[i][j] == 0) //当价值为i费用为j的单词的数量为0的时候则进行下一次循环
continue;
if(count[i][j] * j >= c) //完全背包
{
for(int k = j ; k <= c; k++)
dp[k] = max(dp[k],dp[k-j]+i);
}
else
{
int l = 1;
while(l < count[i][j]) //0 1 背包
{
for(int k = c; k >= l*j; k--)
dp[k] = max(dp[k],dp[k-l*j]+l*i);
count[i][j] -= l;
l <<= 1;
}
for(int k = c; k >= count[i][j]*j; k--)
dp[k] = max(dp[k],dp[k-count[i][j]*j]+count[i][j]*i);
}
}
}
printf("%d\n",dp[c]);
}
return 0;
}