LintCode刷题——卡牌游戏 II(0-1背包)
题目描述
你跟你的朋友在玩一个卡牌游戏,总共有 n
张牌。每张牌的成本为 cost[i]
并且可以对对手造成 damage[i]
的伤害。你总共有 totalMoney
元并且需要造成至少 totalDamage
的伤害才能获胜。每张牌只能使用一次,判断你是否可以取得胜利。
样例
样例1
输入:
cost = [1,2,3,4,5]
damage = [1,2,3,4,5]
totalMoney = 10
totalDamage = 10
输出: true
样例说明: 我们可以使用 [1,4,5] 去造成10点伤害,总花费为10。
Example2
输入:
cost = [1,2]
damage = [3,4]
totalMoney = 10
totalDamage = 10
输出: false
样例说明:我们最多只能造成7点伤害。
标签
背包型动态规划 动态规划
思路
动态规划
1、状态:0-1背包 dp[i][j] 表示前i个卡牌总共有j元能造成的最多伤害
2、状态转移方程:dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - cost[i - 1]] + damage[i - 1])
AC代码
1 public class Solution { 2 /** 3 * @param cost: costs of all cards 4 * @param damage: damage of all cards 5 * @param totalMoney: total of money 6 * @param totalDamage: the damage you need to inflict 7 * @return: Determine if you can win the game 8 */ 9 public boolean cardGame(int[] cost, int[] damage, int totalMoney, int totalDamage) { 10 // Write your code here 11 int n = cost.length; 12 if (n == 0 && totalDamage > 0) { 13 return false; 14 } 15 16 if (totalDamage > 0 && totalMoney == 0) { 17 return false; 18 } 19 20 if (totalDamage == 0) { 21 return true; 22 } 23 24 // 0-1背包 dp[i][j] 表示前i个卡牌总共有j元能造成的最多伤害 25 int[][] dp = new int[n + 1][totalMoney + 1]; 26 27 // 初始化 28 dp[0][0] = 0; 29 30 for (int i = 1; i <= n; i++) { 31 dp[i][0] = 0; 32 dp[0][i] = 0; 33 } 34 35 for (int i = 1; i <= n; i++) { 36 for (int j = 1; j <= totalMoney; j++) { 37 // 设置为无穷小,因为是选最大值 38 // 这里有一点很坑,其实是要找其最大值(不要被题目的至少所迷惑),然后后面比较的时候是用大于等于 39 dp[i][j] = Integer.MIN_VALUE; 40 if (cost[i - 1] > j) { 41 dp[i][j] = dp[i - 1][j]; 42 } else { 43 dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - cost[i - 1]] + damage[i - 1]); 44 } 45 } 46 } 47 48 // 在这里体现出题目中至少这个词的意义 49 if (dp[n][totalMoney] >= totalDamage) { 50 return true; 51 } else { 52 return false; 53 } 54 } 55 }