Dynamic Programming and State Compression (LeetCode #2209 & LeetCode #2212)

本文介绍了如何利用动态规划解决LeetCode中的两道题目,分别是关于最小化白色瓷砖数量和最大化射箭比赛得分的问题。通过定义二维数组dp,并结合状态压缩技巧,有效地解决了这两个问题。对于2209题,通过覆盖地毯减少白色瓷砖;对于2212题,通过优化射击策略最大化Bob的得分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

LeetCode 2209

You are given a 0-indexed binary string floor, which represents the colors of tiles on a floor:

  • floor[i] = '0' denotes that the ith tile of the floor is colored black.
  • On the other hand, floor[i] = '1' denotes that the ith tile of the floor is colored white.

You are also given numCarpets and carpetLen. You have numCarpets black carpets, each of length carpetLen tiles. Cover the tiles with the given carpets such that the number of white tiles still visible is minimum. Carpets may overlap one another.

Return the minimum number of white tiles still visible.

At first sight, there are an infinitely huge amount of combinations available and it seems impossible to test and find out the best one. But yet again, dynamic programming comes and saves the day:

We first define a 2-D integer array: int dp[i][j], storing the minimum number of white tiles from 0-th to the i-th tile after covering j carpet. When we increment i by 1, i.e. extending the current tiles by another one, we will be finding out the minimum of:

1) Cover: Covering the current tile with a carpet, meaning no white tile from the (i - length of carpet +1) to the current one, plus the minimum number of white tiles with j-1 carpet from 0-th to (i - length of carpet)-th tile

2) Jump: Not cover the current tile and get the minimum number of white tiles in the previous tile with the same number of carpets

We will then loop through all the combinations of i and j and get the result in the last element in our dp array:

int minimumWhiteTiles(string s, int nc, int l) {
    int n = s.size();
    vector<vector<int>> dp(n + 1, vector<int>(nc + 1));
    for (int i = 1; i <= n; ++i) {
        for (int k = 0; k <= nc; ++k) {
            int jump = dp[i - 1][k] + s[i - 1] - '0';
            int cover = k > 0 ? dp[max(i - l, 0)][k - 1] : 1000;
            dp[i][k] = min(cover, jump);
        }
    }
    return dp[n][nc];
}

P.S. I did not come up with the solution myself. I just copied it off someone else's solution here :P


LeetCode# 2212

Alice and Bob are opponents in an archery competition. The competition has set the following rules:

  1. Alice first shoots numArrows arrows and then Bob shoots numArrows arrows.
  2. The points are then calculated as follows:
    1. The target has integer scoring sections ranging from 0 to 11 inclusive.
    2. For each section of the target with score k (in between 0 to 11), say Alice and Bob have shot ak and bk arrows on that section respectively. If ak >= bk, then Alice takes k points. If ak < bk, then Bob takes k points.
    3. However, if ak == bk == 0, then nobody takes k points.
  • For example, if Alice and Bob both shot 2 arrows on the section with score 11, then Alice takes 11 points. On the other hand, if Alice shot 0 arrows on the section with score 11 and Bob shot 2 arrows on that same section, then Bob takes 11 points.

You are given the integer numArrows and an integer array aliceArrows of size 12, which represents the number of arrows Alice shot on each scoring section from 0 to 11. Now, Bob wants to maximize the total number of points he can obtain.

Return the array bobArrows which represents the number of arrows Bob shot on each scoring section from 0 to 11. The sum of the values in bobArrows should equal numArrows.

If there are multiple ways for Bob to earn the maximum total points, return any one of them.

There are, of course, better and faster ways of getting a solution to this question but I did find the similarity with the question above (and also the two contests were just 12 hours apart, this is the only thing that comes to my mind...), so I gave dynamic programming a go with it.

We will be defining another 2-D integer array, int dp[i][j], meaning the maximum point Bob will get starting from the 0-th to i-th target with j arrows. To determine whether Bob should win in the current target, we simply take the maximum of:

1) Winning the current target: the score attained in the current target plus the maximum score achievable in the last (i-1) targets with the number of arrows remaining

2) Give up the current target: the same maximum score attainable in the last i-th target with the same number of arrows

The maximum number of arrows is 10^5, which is a pretty huge value if we were to create a 2-D array with that number as one of the dimensions. But here is my implementation anyways:

public:
    vector<int> maximumBobPoints(int numArrows, vector<int>& aliceArrows) {
        int dp[13][numArrows+1];
        memset(dp, 0, sizeof(dp));
        for(int i = 1; i < 13; i ++){
            for(int j = 1; j <= numArrows; j++){
                dp[i][j] = dp[i-1][j];
				// check whether winning in the current target yields a higher value
                if ((j-aliceArrows[i-1] >= 1) && ((dp[i-1][j] & 127) < 
                    (i - 1 + (dp[i-1][j-aliceArrows[i-1] - 1]) & 127) )){
                    dp[i][j] = i-1 + dp[i-1][j-aliceArrows[i-1] - 1] + (1 << (i + 7));
                }
            }
        }
        vector<int> res(12);
        int total = 0;
		// decode the bits
        for(int i = 0; i < 12; i++){
            if(dp[12][numArrows] >> (i + 8) & 1){
                res[i] = aliceArrows[i]+1;
                total += res[i];
            }
        }
		// deal with the arrows that are not used
        if(total != numArrows){
            res[0] += numArrows - total;
        }
        return res;
    }
};

Note that this question is a bit different from the first one. It requires us to output an array indicating how many arrows should Bob shoot in each target. So, I did a little bit of modification.


State compression

To be honest, I have no idea what "state compression" was during my implementation. I just wanted a way to save space and pass on the combination at the same time. My idea is that we can use some bits in front of the maximum points achievable to indicate whether Bob should win in each round. Since the maximum number of points that Bob could get is 0+1+2+...+11 = 66, which is less than 7 bits. We can make use of the 8-th to 20-th bits, a total of 12 bits, in front to store a bit pattern, with 0 and 1 indicating whether Bob should take that round or not.


Special thanks to Angus gor, for explaining the solution of the first question to me TT

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值