题目地址: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; }