【Lintcode】1448. Card Game

题目地址:

https://www.lintcode.com/problem/card-game/description

给定 n n n个物品,其价值为数组 A A A,成本为数组 B B B,问在给定总预算 c c c和最小总价值 p p p的情况下,有多少个组合可以使得总成本是小于 c c c,并且总价值是大于 p p p的。题目保证每个物品的价值和成本都是非负的(注意,这里可以是 0 0 0)。答案模 1 0 9 + 7 10^9+7 109+7后返回。

思路是动态规划。设 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]是前 i i i个物品(从 0 0 0开始计数),总价值大于等于 j j j并且成本恰好等于 k k k的方案数。那么根据第 i i i个物品是否选,可以分为两种情况,如果不选,那么方案数就是 f [ i − 1 ] [ j ] [ k ] f[i-1][j][k] f[i1][j][k];如果选,那么方案数就是 f [ i − 1 ] [ max ⁡ { 0 , j − A [ i ] } ] [ k − B [ i ] ] f[i-1][\max\{0,j-A[i]\}][k-B[i]] f[i1][max{0,jA[i]}][kB[i]],所以就有: f [ i ] [ j ] [ k ] = f [ i − 1 ] [ j ] [ k ] + f [ i − 1 ] [ max ⁡ { 0 , j − A [ i ] } ] [ k − B [ i ] ] f[i][j][k]=f[i-1][j][k]+f[i-1][\max\{0,j-A[i]\}][k-B[i]] f[i][j][k]=f[i1][j][k]+f[i1][max{0,jA[i]}][kB[i]]边界条件,考虑第 0 0 0个物品是否选。如果不选,则 f [ 0 ] [ 0 ] [ 0 ] = 1 f[0][0][0]=1 f[0][0][0]=1,别的 f [ 0 ] [ . > 0 ] [ 0 ] = 0 f[0][.>0][0]=0 f[0][.>0][0]=0;如果选,则 f [ 0 ] [ . ≤ A [ 0 ] ] [ B [ i ] ] = 1 f[0][.\le A[0]][B[i]]=1 f[0][.A[0]][B[i]]=1,所以算 f [ 0 ] f[0] f[0]的时候,要将两种情况加总。代码如下:

public class Solution {
    /**
     * @param n:           The number of cards
     * @param totalProfit: The totalProfit
     * @param totalCost:   The totalCost
     * @param a:           The profit of cards
     * @param b:           The cost of cards
     * @return: Return the number of legal plan
     */
    public int numOfPlan(int n, int totalProfit, int totalCost, int[] a, int[] b) {
        // Write your code here
        int MOD = (int) (1E9 + 7);
        
        // dp[i][j][k]是从前i + 1个物品里选,价值大于等于j的且成本恰好等于k的组合总数
        int[][][] dp = new int[n][totalProfit + 2][totalCost];
        
        // 如果第0个物品不选
        dp[0][0][0] = 1;
        for (int i = 0; i <= Math.min(a[0], totalProfit + 1); i++) {
        	// 这里要注意b[0] = 0的情况,所以要写成 += 1
            dp[0][i][b[0]] += 1;
        }
        
        for (int i = 1; i < n; i++) {
            for (int j = 0; j <= totalProfit + 1; j++) {
                for (int k = 0; k < totalCost; k++) {
                    dp[i][j][k] = dp[i - 1][j][k];
                    if (k >= b[i]) {
                        dp[i][j][k] += dp[i - 1][Math.max(0, j - a[i])][k - b[i]];
                    }
                    
                    dp[i][j][k] %= MOD;
                }
            }
        }
        
        int res = 0;
        for (int i = 0; i < totalCost; i++) {
            res += dp[n - 1][totalProfit + 1][i];
            res %= MOD;
        }
        
        return res;
    }
}

时空复杂度 O ( n p c ) O(npc) O(npc)

可以用滚动数组优化。代码如下:

public class Solution {
    /**
     * @param n:           The number of cards
     * @param totalProfit: The totalProfit
     * @param totalCost:   The totalCost
     * @param a:           The profit of cards
     * @param b:           The cost of cards
     * @return: Return the number of legal plan
     */
    public int numOfPlan(int n, int totalProfit, int totalCost, int[] a, int[] b) {
        // Write your code here
        int MOD = (int) (1E9 + 7);
        // dp[i][j][k]是从前i + 1个物品里选,价值大于等于j的且成本恰好等于k的组合总数
        int[][][] dp = new int[2][totalProfit + 2][totalCost];
        
        dp[0][0][0] = 1;
        for (int i = 0; i <= Math.min(a[0], totalProfit + 1); i++) {
            dp[0][i][b[0]] += 1;
        }
        
        for (int i = 1; i < n; i++) {
            for (int j = 0; j <= totalProfit + 1; j++) {
                for (int k = 0; k < totalCost; k++) {
                    dp[i & 1][j][k] = dp[i - 1 & 1][j][k];
                    if (k >= b[i]) {
                        dp[i & 1][j][k] += dp[i - 1 & 1][Math.max(0, j - a[i])][k - b[i]];
                    }
                    
                    dp[i & 1][j][k] %= MOD;
                }
            }
        }
        
        int res = 0;
		for (int i = 0; i < totalCost; i++) {
            res += dp[n - 1 & 1][totalProfit + 1][i];
            res %= MOD;
        }        

        return res;
    }
}

时间复杂度不变,空间 O ( p c ) O(pc) O(pc)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private int[] cards = {R.drawable.card1, R.drawable.card2, R.drawable.card3, R.drawable.card1, R.drawable.card5, R.drawable.card6, R.drawable.card7, R.drawable.card8}; private int[] cardIds = {R.id.card1, R.id.card2, R.id.card3, R.id.card4, R.id.card5, R.id.card6, R.id.card7, R.id.card8}; private int[] cardStatus = new int[8]; private int firstCard = -1, secondCard = -1; private boolean isClickable = true; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); for (int i = 0; i < cardIds.length; i++) { ImageView card = findViewById(cardIds[i]); card.setTag(i); card.setOnClickListener(this); } Collections.shuffle(Arrays.asList(cards)); } @Override public void onClick(View v) { if (!isClickable) { return; } int id = (int) v.getTag(); if (cardStatus[id] == 1) { return; } if (firstCard == -1) { firstCard = id; ImageView card = findViewById(cardIds[id]); card.setImageResource(cards[id]); } else { secondCard = id; ImageView card = findViewById(cardIds[id]); card.setImageResource(cards[id]); if (cards[firstCard] == cards[secondCard]) { cardStatus[firstCard] = 1; cardStatus[secondCard] = 1; firstCard = -1; secondCard = -1; if (checkWin()) { Toast.makeText(this, "You Win!", Toast.LENGTH_SHORT).show(); } } else { isClickable = false; Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { ImageView card1 = findViewById(cardIds[firstCard]); ImageView card2 = findViewById(cardIds[secondCard]); card1.setImageResource(R.drawable.card_back); card2.setImageResource(R.drawable.card_back); firstCard = -1; secondCard = -1; isClickable = true; } }, 1000); } } } private boolean checkWin() { for (int i = 0; i < cardStatus.length; i++) { if (cardStatus[i] == 0) { return false; } } return true; } }请帮我优化这段代码
06-08

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值