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 theith
tile of the floor is colored black.- On the other hand,
floor[i] = '1'
denotes that theith
tile of the floor is colored white.You are also given
numCarpets
andcarpetLen
. You havenumCarpets
black carpets, each of lengthcarpetLen
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:
- Alice first shoots
numArrows
arrows and then Bob shootsnumArrows
arrows.- The points are then calculated as follows:
- The target has integer scoring sections ranging from
0
to11
inclusive.- For each section of the target with score
k
(in between0
to11
), say Alice and Bob have shotak
andbk
arrows on that section respectively. Ifak >= bk
, then Alice takesk
points. Ifak < bk
, then Bob takesk
points.- However, if
ak == bk == 0
, then nobody takesk
points.
For example, if Alice and Bob both shot
2
arrows on the section with score11
, then Alice takes11
points. On the other hand, if Alice shot0
arrows on the section with score11
and Bob shot2
arrows on that same section, then Bob takes11
points.You are given the integer
numArrows
and an integer arrayaliceArrows
of size12
, which represents the number of arrows Alice shot on each scoring section from0
to11
. 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 from0
to11
. The sum of the values inbobArrows
should equalnumArrows
.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