链接:https://www.nowcoder.com/acm/contest/74/B
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
空间限制:C/C++ 32768K,其他语言65536K
64bit IO Format: %lld
题目描述
Taotao的电脑带不动绝地求生,所以taotao只能去玩pc版的荒野行动了,和绝地求生一样,游戏人物本身可以携带一定重量m的物品,装备背包
之后可以多携带h(h为0代表没有装备背包)重量的东西。玩了几天taotao发现了一个BUG,当装备背包之后,如果可携带重量没有满,就
可以拿一个任意重的东西。(解释看样例)有一天taotao空降到了一个奇怪的岛上,岛上有n件装备,每个装备都有重量Wi和威力值Vi,但taotao
不认识这些装备,所以他来求助你,挑选威力最大的装备,帮助他吃鸡。
输入描述:
本题有多组输入(小于10),当n=0时结束输入。 第一行输入n,m,h。n,m,h为整数,并且0<=n,m,h<=100, 接下来n行,每行输入第i个物品的物品的重量Wi和威力值Vi。0<=Wi,Vi<=100.
输出描述:
输出最大威力值,每组输出一行
这道题目考察的是 01 背包,和 01 背包不同的是,这里的容量不确定,要分类:
背包容量为 0 , 总容量为手上的容量,直接 01 背包;
背包容量不为0,因为 0 <= 物品威力 <= 100 ,都是整数。所以如果有的物品威力为 0 , 可能为了故意不装满背包而最后选了这件物品,就不是最大值。所以,要考虑最后不拿一件物品的情况。
最后不拿一件物品,总容量就是 m+h ,最大值是 01 背包;
最后拿一件物品,总容量上限是 m+h-1 , 最大值是 01 背包+最后拿的那件物品的威力 ;
多种情况取最大值。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std ;
int dp[202] , cost[101] , value[101] ;
int main(){
int n , m , h , i , j , k ;
while( cin >> n && n ){
cin >> m >> h ;
for( i = 1 ; i <= n ; ++i )
cin >> cost[i] >> value[i] ;
memset( dp , 0 , sizeof( dp ) ) ;
if( h == 0 ){
for( i = 1 ; i <= n ; ++i )
for( j = m ; j >= cost[i] ; --j ) // 从 m 开始递减,避免重复,不懂先打表
dp[j] = max( dp[j] , dp[j-cost[i]] + value[i] ) ;
printf( "%d\n" , dp[m] ) ; // 最大容量为 m 时可以选择的最大威力的装备
}
else{
for( int i = 1 ; i <= n ; ++i )
for( int j = m+h ; j >= cost[i] ; --j )
dp[j] = max( dp[j] , dp[j-cost[i]] + value[i] ) ; // 如果最后不选择带一件物品
int ans = dp[m+h] ;
for( k = 1 ; k <= n ; ++k ){ // 枚举 n 件物品,如果不选这件物品,而是最后带上任意重的那件
memset( dp , 0 , sizeof( dp ) ) ; // 每次 01 背包都要清空
for( i = 1 ; i <= n ; ++i )
if( i != k ) // 暂且不选第 k 件
for( j = m+h-1 ; j >= cost[i] ; --j ) // 只有当背包没装满,也就是背包的容量最大是 m+h-1
dp[j] = max( dp[j] , dp[j-cost[i]] + value[i] ) ;
ans = max( ans , value[k] + dp[m+h-1] ) ; // 最后背包没装满,带上第 k 件,加上背包和手可以选择的最大威力装备
}
cout << ans << endl ;
}
}
return 0 ;
}