From 7a4685aeab48c2bbbb9c17413dd2289889820d63 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Fri, 13 Sep 2024 11:01:43 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.2403 No.2403.Minimum Time to Kill All Monsters --- .../README.md | 258 ++++++++--------- .../README_EN.md | 262 +++++++++--------- .../Solution.cpp | 45 ++- .../Solution.go | 24 +- .../Solution.java | 29 +- .../Solution.py | 16 +- .../Solution.ts | 41 ++- .../Solution2.cpp | 15 +- .../Solution2.go | 20 +- .../Solution2.java | 16 +- .../Solution2.py | 14 +- .../Solution2.ts | 25 +- 12 files changed, 381 insertions(+), 384 deletions(-) diff --git a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/README.md b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/README.md index 3c24e0e78b8ea..2af89016ca1d3 100644 --- a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/README.md +++ b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/README.md @@ -94,13 +94,20 @@ tags: -### 方法一:状态压缩 + 记忆化搜索或动态规划 +### 方法一:状态压缩 + 记忆化搜索 -由于打怪才能增加每天法力的收益 $gain$,不同的打怪顺序对结果有影响,需要枚举。注意到题目的数据范围较小,考虑使用状态压缩动态规划求解。 +我们注意带,怪物的数量最多为 $17$,这意味着我们可以使用一个 $17$ 位的二进制数来表示怪物的状态,其中第 $i$ 位为 $1$ 表示第 $i$ 个怪物还活着,为 $0$ 表示第 $i$ 个怪物已经被击败。 -我们定义状态 $mask$ 表示当前已经打怪的情况,其二进制中的 $1$ 表示已经被打倒的怪物,而 $0$ 表示未被打倒的怪物。 +我们设计一个函数 $\textit{dfs}(\textit{mask})$,表示当前怪物的状态为 $\textit{mask}$ 时,打败所有怪物所需的最少天数。那么答案就是 $\textit{dfs}(2^n - 1)$,其中 $n$ 为怪物的数量。 -时间复杂度 $O(n \times 2^n)$,空间复杂度 $O(2^n)$。其中 $n$ 是怪物数量。 +函数 $\textit{dfs}(\textit{mask})$ 的计算方式如下: + +- 如果 $\textit{mask} = 0$,表示所有怪物都已经被击败,返回 $0$; +- 否则,我们枚举每个怪物 $i$,如果第 $i$ 个怪物还活着,那么我们可以选择击败第 $i$ 个怪物,然后递归计算 $\textit{dfs}(\textit{mask} \oplus 2^i)$,并更新答案为 $\textit{ans} = \min(\textit{ans}, \textit{dfs}(\textit{mask} \oplus 2^i) + \lceil \frac{x}{\textit{gain}} \rceil)$,其中 $x$ 为第 $i$ 个怪物的力量,而 $\textit{gain} = 1 + (n - \textit{mask}.\textit{bitCount}())$,表示当前每天可以获得的法力值。 + +最后,我们返回 $\textit{dfs}(2^n - 1)$。 + +时间复杂度 $O(2^n \times n)$,空间复杂度 $O(2^n)$。其中 $n$ 为怪物的数量。 @@ -110,18 +117,18 @@ tags: class Solution: def minimumTime(self, power: List[int]) -> int: @cache - def dfs(mask): - cnt = mask.bit_count() - if cnt == len(power): + def dfs(mask: int) -> int: + if mask == 0: return 0 ans = inf - for i, v in enumerate(power): - if mask & (1 << i): - continue - ans = min(ans, dfs(mask | 1 << i) + (v + cnt) // (cnt + 1)) + gain = 1 + (n - mask.bit_count()) + for i, x in enumerate(power): + if mask >> i & 1: + ans = min(ans, dfs(mask ^ (1 << i)) + (x + gain - 1) // gain) return ans - return dfs(0) + n = len(power) + return dfs((1 << n) - 1) ``` #### Java @@ -129,34 +136,31 @@ class Solution: ```java class Solution { private int n; - private long[] f; private int[] power; + private Long[] f; public long minimumTime(int[] power) { n = power.length; - f = new long[1 << n]; - Arrays.fill(f, -1); this.power = power; - return dfs(0); + f = new Long[1 << n]; + return dfs((1 << n) - 1); } private long dfs(int mask) { - if (f[mask] != -1) { - return f[mask]; - } - int cnt = Integer.bitCount(mask); - if (cnt == n) { + if (mask == 0) { return 0; } - long ans = Long.MAX_VALUE; + if (f[mask] != null) { + return f[mask]; + } + f[mask] = Long.MAX_VALUE; + int gain = 1 + (n - Integer.bitCount(mask)); for (int i = 0; i < n; ++i) { - if (((mask >> i) & 1) == 1) { - continue; + if ((mask >> i & 1) == 1) { + f[mask] = Math.min(f[mask], dfs(mask ^ 1 << i) + (power[i] + gain - 1) / gain); } - ans = Math.min(ans, dfs(mask | 1 << i) + (power[i] + cnt) / (cnt + 1)); } - f[mask] = ans; - return ans; + return f[mask]; } } ``` @@ -164,32 +168,29 @@ class Solution { #### C++ ```cpp -using ll = long long; - class Solution { public: - vector f; - vector power; - int n; - long long minimumTime(vector& power) { - n = power.size(); - f.assign(1 << n, -1); - this->power = power; - return dfs(0); - } - - ll dfs(int mask) { - if (f[mask] != -1) return f[mask]; - int cnt = __builtin_popcount(mask); - if (cnt == n) return 0; - ll ans = LONG_MAX; - for (int i = 0; i < n; ++i) { - if ((mask >> i) & 1) continue; - ans = min(ans, dfs(mask | 1 << i) + (power[i] + cnt) / (cnt + 1)); - } - f[mask] = ans; - return ans; + int n = power.size(); + long long f[1 << n]; + memset(f, -1, sizeof(f)); + auto dfs = [&](auto&& dfs, int mask) -> long long { + if (mask == 0) { + return 0; + } + if (f[mask] != -1) { + return f[mask]; + } + f[mask] = LLONG_MAX; + int gain = 1 + (n - __builtin_popcount(mask)); + for (int i = 0; i < n; ++i) { + if (mask >> i & 1) { + f[mask] = min(f[mask], dfs(dfs, mask ^ (1 << i)) + (power[i] + gain - 1) / gain); + } + } + return f[mask]; + }; + return dfs(dfs, (1 << n) - 1); } }; ``` @@ -205,24 +206,22 @@ func minimumTime(power []int) int64 { } var dfs func(mask int) int64 dfs = func(mask int) int64 { + if mask == 0 { + return 0 + } if f[mask] != -1 { return f[mask] } - cnt := bits.OnesCount(uint(mask)) - if cnt == n { - return 0 - } - var ans int64 = math.MaxInt64 - for i, v := range power { - if (mask >> i & 1) == 1 { - continue + f[mask] = 1e18 + gain := 1 + (n - bits.OnesCount(uint(mask))) + for i, x := range power { + if mask>>i&1 == 1 { + f[mask] = min(f[mask], dfs(mask^(1< { + if (mask === 0) { return 0; } - let ans = Infinity; + if (f[mask] !== -1) { + return f[mask]; + } + f[mask] = Infinity; + const gain = 1 + (n - bitCount(mask)); for (let i = 0; i < n; ++i) { if ((mask >> i) & 1) { - continue; + f[mask] = Math.min(f[mask], dfs(mask ^ (1 << i)) + Math.ceil(power[i] / gain)); } - ans = Math.min(ans, dfs(mask | (1 << i)) + Math.ceil(power[i] / (cnt + 1))); } - f[mask] = ans; - return ans; - } - return dfs(0); + return f[mask]; + }; + return dfs((1 << n) - 1); } -function bitCount(x) { - let cnt = 0; - for (let i = 0; i < 32; ++i) { - if ((x >> i) & 1) { - ++cnt; - } - } - return cnt; +function bitCount(i: number): number { + i = i - ((i >>> 1) & 0x55555555); + i = (i & 0x33333333) + ((i >>> 2) & 0x33333333); + i = (i + (i >>> 4)) & 0x0f0f0f0f; + i = i + (i >>> 8); + i = i + (i >>> 16); + return i & 0x3f; } ``` @@ -270,7 +266,15 @@ function bitCount(x) { -### 方法二 +### 方法二:状态压缩 + 动态规划 + +我们可以将方法一中的记忆化搜索改为动态规划,定义 $f[\textit{mask}]$ 表示当前怪物的状态为 $\textit{mask}$ 时,打败所有怪物所需的最少天数。其中 $\textit{mask}$ 是一个 $n$ 位的二进制数,其中第 $i$ 位为 $1$ 表示第 $i$ 个怪物已被击败,为 $0$ 表示第 $i$ 个怪物还活着。初始时 $f[0] = 0$,其余 $f[\textit{mask}] = +\infty$。答案即为 $f[2^n - 1]$。 + +我们在 $[1, 2^n - 1]$ 的范围内枚举 $\textit{mask}$,对于每个 $\textit{mask}$,我们枚举每个怪物 $i$,如果第 $i$ 个怪物被击败,那么它可以从上一个状态 $\textit{mask} \oplus 2^i$ 转移过来,转移的代价为 $(\textit{power}[i] + \textit{gain} - 1) / \textit{gain}$,其中 $\textit{gain} = \textit{mask}.\textit{bitCount}()$。 + +最后,返回 $f[2^n - 1]$。 + +时间复杂度 $O(2^n \times n)$,空间复杂度 $O(2^n)$。其中 $n$ 为怪物的数量。 @@ -280,14 +284,14 @@ function bitCount(x) { class Solution: def minimumTime(self, power: List[int]) -> int: n = len(power) - dp = [inf] * (1 << n) - dp[0] = 0 + f = [inf] * (1 << n) + f[0] = 0 for mask in range(1, 1 << n): - cnt = mask.bit_count() - for i, v in enumerate(power): - if (mask >> i) & 1: - dp[mask] = min(dp[mask], dp[mask ^ (1 << i)] + (v + cnt - 1) // cnt) - return dp[-1] + gain = mask.bit_count() + for i, x in enumerate(power): + if mask >> i & 1: + f[mask] = min(f[mask], f[mask ^ (1 << i)] + (x + gain - 1) // gain) + return f[-1] ``` #### Java @@ -296,18 +300,18 @@ class Solution: class Solution { public long minimumTime(int[] power) { int n = power.length; - long[] dp = new long[1 << n]; - Arrays.fill(dp, Long.MAX_VALUE); - dp[0] = 0; + long[] f = new long[1 << n]; + Arrays.fill(f, Long.MAX_VALUE); + f[0] = 0; for (int mask = 1; mask < 1 << n; ++mask) { - int cnt = Integer.bitCount(mask); + int gain = Integer.bitCount(mask); for (int i = 0; i < n; ++i) { - if (((mask >> i) & 1) == 1) { - dp[mask] = Math.min(dp[mask], dp[mask ^ (1 << i)] + (power[i] + cnt - 1) / cnt); + if ((mask >> i & 1) == 1) { + f[mask] = Math.min(f[mask], f[mask ^ 1 << i] + (power[i] + gain - 1) / gain); } } } - return dp[(1 << n) - 1]; + return f[(1 << n) - 1]; } } ``` @@ -319,17 +323,18 @@ class Solution { public: long long minimumTime(vector& power) { int n = power.size(); - vector dp(1 << n, LONG_MAX); - dp[0] = 0; + long long f[1 << n]; + memset(f, 0x3f, sizeof(f)); + f[0] = 0; for (int mask = 1; mask < 1 << n; ++mask) { - int cnt = __builtin_popcount(mask); + int gain = __builtin_popcount(mask); for (int i = 0; i < n; ++i) { - if ((mask >> i) & 1) { - dp[mask] = min(dp[mask], dp[mask ^ (1 << i)] + (power[i] + cnt - 1) / cnt); + if (mask >> i & 1) { + f[mask] = min(f[mask], f[mask ^ (1 << i)] + (power[i] + gain - 1) / gain); } } } - return dp[(1 << n) - 1]; + return f[(1 << n) - 1]; } }; ``` @@ -339,20 +344,20 @@ public: ```go func minimumTime(power []int) int64 { n := len(power) - dp := make([]int64, 1<> i) & 1) == 1 { - dp[mask] = min(dp[mask], dp[mask^(1<>i&1 == 1 { + f[mask] = min(f[mask], f[mask^(1<> i) & 1) { - dp[mask] = Math.min(dp[mask], dp[mask ^ (1 << i)] + Math.ceil(power[i] / cnt)); + f[mask] = Math.min(f[mask], f[mask ^ (1 << i)] + Math.ceil(power[i] / gain)); } } } - return dp[dp.length - 1]; + return f.at(-1)!; } -function bitCount(x) { - let cnt = 0; - for (let i = 0; i < 32; ++i) { - if ((x >> i) & 1) { - ++cnt; - } - } - return cnt; +function bitCount(i: number): number { + i = i - ((i >>> 1) & 0x55555555); + i = (i & 0x33333333) + ((i >>> 2) & 0x33333333); + i = (i + (i >>> 4)) & 0x0f0f0f0f; + i = i + (i >>> 8); + i = i + (i >>> 16); + return i & 0x3f; } ``` diff --git a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/README_EN.md b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/README_EN.md index 0bef7e39c7188..80a69c41e6c7e 100644 --- a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/README_EN.md +++ b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/README_EN.md @@ -43,7 +43,7 @@ tags: - Day 2: Gain 2 mana points to get a total of 2 mana points. - Day 3: Gain 2 mana points to get a total of 4 mana points. Spend all mana points to kill the 3rd monster. - Day 4: Gain 3 mana points to get a total of 3 mana points. Spend all mana points to kill the 1st monster. -It can be proven that 4 is the minimum number of days needed. +It can be proven that 4 is the minimum number of days needed.

Example 2:

@@ -56,7 +56,7 @@ It can be proven that 4 is the minimum number of days needed. - Day 2: Gain 2 mana points to get a total of 2 mana points. Spend all mana points to kill the 2nd monster. - Day 3: Gain 3 mana points to get a total of 3 mana points. - Day 4: Gain 3 mana points to get a total of 6 mana points. Spend all mana points to kill the 3rd monster. -It can be proven that 4 is the minimum number of days needed. +It can be proven that 4 is the minimum number of days needed.

Example 3:

@@ -88,13 +88,20 @@ It can be proven that 6 is the minimum number of days needed. -### Solution 1: State Compression + Memorization Search or Dynamic Programming +### Solution 1: State Compression + Memoization Search -Since defeating monsters can increase the daily magic power gain $gain$, the order of defeating monsters affects the result, so we need to enumerate. Noting that the data range of the problem is small, we consider using state compression dynamic programming to solve it. +We note that the number of monsters is at most $17$, which means we can use a 17-bit binary number to represent the state of the monsters. The $i$-th bit being $1$ indicates that the $i$-th monster is still alive, and $0$ indicates that the $i$-th monster has been defeated. -We define a state $mask$ to represent the current situation of defeating monsters. In its binary representation, $1$ represents the monsters that have been defeated, and $0$ represents the monsters that have not been defeated. +We design a function $\textit{dfs}(\textit{mask})$ to represent the minimum number of days needed to defeat all monsters when the current state of the monsters is $\textit{mask}$. The answer is $\textit{dfs}(2^n - 1)$, where $n$ is the number of monsters. -The time complexity is $O(n \times 2^n)$, and the space complexity is $O(2^n)$. Here, $n$ is the number of monsters. +The calculation of the function $\textit{dfs}(\textit{mask})$ is as follows: + +- If $\textit{mask} = 0$, it means all monsters have been defeated, return $0$; +- Otherwise, we enumerate each monster $i$. If the $i$-th monster is still alive, we can choose to defeat the $i$-th monster, then recursively calculate $\textit{dfs}(\textit{mask} \oplus 2^i)$, and update the answer to $\textit{ans} = \min(\textit{ans}, \textit{dfs}(\textit{mask} \oplus 2^i) + \lceil \frac{x}{\textit{gain}} \rceil)$, where $x$ is the strength of the $i$-th monster, and $\textit{gain} = 1 + (n - \textit{mask}.\textit{bit\_count}())$ represents the current daily mana gain. + +Finally, we return $\textit{dfs}(2^n - 1)$. + +The time complexity is $O(2^n \times n)$, and the space complexity is $O(2^n)$. Here, $n$ is the number of monsters. @@ -104,18 +111,18 @@ The time complexity is $O(n \times 2^n)$, and the space complexity is $O(2^n)$. class Solution: def minimumTime(self, power: List[int]) -> int: @cache - def dfs(mask): - cnt = mask.bit_count() - if cnt == len(power): + def dfs(mask: int) -> int: + if mask == 0: return 0 ans = inf - for i, v in enumerate(power): - if mask & (1 << i): - continue - ans = min(ans, dfs(mask | 1 << i) + (v + cnt) // (cnt + 1)) + gain = 1 + (n - mask.bit_count()) + for i, x in enumerate(power): + if mask >> i & 1: + ans = min(ans, dfs(mask ^ (1 << i)) + (x + gain - 1) // gain) return ans - return dfs(0) + n = len(power) + return dfs((1 << n) - 1) ``` #### Java @@ -123,34 +130,31 @@ class Solution: ```java class Solution { private int n; - private long[] f; private int[] power; + private Long[] f; public long minimumTime(int[] power) { n = power.length; - f = new long[1 << n]; - Arrays.fill(f, -1); this.power = power; - return dfs(0); + f = new Long[1 << n]; + return dfs((1 << n) - 1); } private long dfs(int mask) { - if (f[mask] != -1) { - return f[mask]; - } - int cnt = Integer.bitCount(mask); - if (cnt == n) { + if (mask == 0) { return 0; } - long ans = Long.MAX_VALUE; + if (f[mask] != null) { + return f[mask]; + } + f[mask] = Long.MAX_VALUE; + int gain = 1 + (n - Integer.bitCount(mask)); for (int i = 0; i < n; ++i) { - if (((mask >> i) & 1) == 1) { - continue; + if ((mask >> i & 1) == 1) { + f[mask] = Math.min(f[mask], dfs(mask ^ 1 << i) + (power[i] + gain - 1) / gain); } - ans = Math.min(ans, dfs(mask | 1 << i) + (power[i] + cnt) / (cnt + 1)); } - f[mask] = ans; - return ans; + return f[mask]; } } ``` @@ -158,32 +162,29 @@ class Solution { #### C++ ```cpp -using ll = long long; - class Solution { public: - vector f; - vector power; - int n; - long long minimumTime(vector& power) { - n = power.size(); - f.assign(1 << n, -1); - this->power = power; - return dfs(0); - } - - ll dfs(int mask) { - if (f[mask] != -1) return f[mask]; - int cnt = __builtin_popcount(mask); - if (cnt == n) return 0; - ll ans = LONG_MAX; - for (int i = 0; i < n; ++i) { - if ((mask >> i) & 1) continue; - ans = min(ans, dfs(mask | 1 << i) + (power[i] + cnt) / (cnt + 1)); - } - f[mask] = ans; - return ans; + int n = power.size(); + long long f[1 << n]; + memset(f, -1, sizeof(f)); + auto dfs = [&](auto&& dfs, int mask) -> long long { + if (mask == 0) { + return 0; + } + if (f[mask] != -1) { + return f[mask]; + } + f[mask] = LLONG_MAX; + int gain = 1 + (n - __builtin_popcount(mask)); + for (int i = 0; i < n; ++i) { + if (mask >> i & 1) { + f[mask] = min(f[mask], dfs(dfs, mask ^ (1 << i)) + (power[i] + gain - 1) / gain); + } + } + return f[mask]; + }; + return dfs(dfs, (1 << n) - 1); } }; ``` @@ -199,24 +200,22 @@ func minimumTime(power []int) int64 { } var dfs func(mask int) int64 dfs = func(mask int) int64 { + if mask == 0 { + return 0 + } if f[mask] != -1 { return f[mask] } - cnt := bits.OnesCount(uint(mask)) - if cnt == n { - return 0 - } - var ans int64 = math.MaxInt64 - for i, v := range power { - if (mask >> i & 1) == 1 { - continue + f[mask] = 1e18 + gain := 1 + (n - bits.OnesCount(uint(mask))) + for i, x := range power { + if mask>>i&1 == 1 { + f[mask] = min(f[mask], dfs(mask^(1< { + if (mask === 0) { return 0; } - let ans = Infinity; + if (f[mask] !== -1) { + return f[mask]; + } + f[mask] = Infinity; + const gain = 1 + (n - bitCount(mask)); for (let i = 0; i < n; ++i) { if ((mask >> i) & 1) { - continue; + f[mask] = Math.min(f[mask], dfs(mask ^ (1 << i)) + Math.ceil(power[i] / gain)); } - ans = Math.min(ans, dfs(mask | (1 << i)) + Math.ceil(power[i] / (cnt + 1))); } - f[mask] = ans; - return ans; - } - return dfs(0); + return f[mask]; + }; + return dfs((1 << n) - 1); } -function bitCount(x) { - let cnt = 0; - for (let i = 0; i < 32; ++i) { - if ((x >> i) & 1) { - ++cnt; - } - } - return cnt; +function bitCount(i: number): number { + i = i - ((i >>> 1) & 0x55555555); + i = (i & 0x33333333) + ((i >>> 2) & 0x33333333); + i = (i + (i >>> 4)) & 0x0f0f0f0f; + i = i + (i >>> 8); + i = i + (i >>> 16); + return i & 0x3f; } ``` @@ -264,7 +260,15 @@ function bitCount(x) { -### Solution 2 +### Solution 2: State Compression + Dynamic Programming + +We can convert the memoization search in Solution 1 to dynamic programming. Define $f[\textit{mask}]$ to represent the minimum number of days needed to defeat all monsters when the current state of the monsters is $\textit{mask}$. Here, $\textit{mask}$ is an $n$-bit binary number, where the $i$-th bit being $1$ indicates that the $i$-th monster has been defeated, and $0$ indicates that the $i$-th monster is still alive. Initially, $f[0] = 0$, and the rest $f[\textit{mask}] = +\infty$. The answer is $f[2^n - 1]$. + +We enumerate $\textit{mask}$ in the range $[1, 2^n - 1]$. For each $\textit{mask}$, we enumerate each monster $i$. If the $i$-th monster is defeated, it can be transferred from the previous state $\textit{mask} \oplus 2^i$, with a transfer cost of $(\textit{power}[i] + \textit{gain} - 1) / \textit{gain}$, where $\textit{gain} = \textit{mask}.\textit{bitCount}()$. + +Finally, return $f[2^n - 1]$. + +The time complexity is $O(2^n \times n)$, and the space complexity is $O(2^n)$. Here, $n$ is the number of monsters. @@ -274,14 +278,14 @@ function bitCount(x) { class Solution: def minimumTime(self, power: List[int]) -> int: n = len(power) - dp = [inf] * (1 << n) - dp[0] = 0 + f = [inf] * (1 << n) + f[0] = 0 for mask in range(1, 1 << n): - cnt = mask.bit_count() - for i, v in enumerate(power): - if (mask >> i) & 1: - dp[mask] = min(dp[mask], dp[mask ^ (1 << i)] + (v + cnt - 1) // cnt) - return dp[-1] + gain = mask.bit_count() + for i, x in enumerate(power): + if mask >> i & 1: + f[mask] = min(f[mask], f[mask ^ (1 << i)] + (x + gain - 1) // gain) + return f[-1] ``` #### Java @@ -290,18 +294,18 @@ class Solution: class Solution { public long minimumTime(int[] power) { int n = power.length; - long[] dp = new long[1 << n]; - Arrays.fill(dp, Long.MAX_VALUE); - dp[0] = 0; + long[] f = new long[1 << n]; + Arrays.fill(f, Long.MAX_VALUE); + f[0] = 0; for (int mask = 1; mask < 1 << n; ++mask) { - int cnt = Integer.bitCount(mask); + int gain = Integer.bitCount(mask); for (int i = 0; i < n; ++i) { - if (((mask >> i) & 1) == 1) { - dp[mask] = Math.min(dp[mask], dp[mask ^ (1 << i)] + (power[i] + cnt - 1) / cnt); + if ((mask >> i & 1) == 1) { + f[mask] = Math.min(f[mask], f[mask ^ 1 << i] + (power[i] + gain - 1) / gain); } } } - return dp[(1 << n) - 1]; + return f[(1 << n) - 1]; } } ``` @@ -313,17 +317,18 @@ class Solution { public: long long minimumTime(vector& power) { int n = power.size(); - vector dp(1 << n, LONG_MAX); - dp[0] = 0; + long long f[1 << n]; + memset(f, 0x3f, sizeof(f)); + f[0] = 0; for (int mask = 1; mask < 1 << n; ++mask) { - int cnt = __builtin_popcount(mask); + int gain = __builtin_popcount(mask); for (int i = 0; i < n; ++i) { - if ((mask >> i) & 1) { - dp[mask] = min(dp[mask], dp[mask ^ (1 << i)] + (power[i] + cnt - 1) / cnt); + if (mask >> i & 1) { + f[mask] = min(f[mask], f[mask ^ (1 << i)] + (power[i] + gain - 1) / gain); } } } - return dp[(1 << n) - 1]; + return f[(1 << n) - 1]; } }; ``` @@ -333,20 +338,20 @@ public: ```go func minimumTime(power []int) int64 { n := len(power) - dp := make([]int64, 1<> i) & 1) == 1 { - dp[mask] = min(dp[mask], dp[mask^(1<>i&1 == 1 { + f[mask] = min(f[mask], f[mask^(1<> i) & 1) { - dp[mask] = Math.min(dp[mask], dp[mask ^ (1 << i)] + Math.ceil(power[i] / cnt)); + f[mask] = Math.min(f[mask], f[mask ^ (1 << i)] + Math.ceil(power[i] / gain)); } } } - return dp[dp.length - 1]; + return f.at(-1)!; } -function bitCount(x) { - let cnt = 0; - for (let i = 0; i < 32; ++i) { - if ((x >> i) & 1) { - ++cnt; - } - } - return cnt; +function bitCount(i: number): number { + i = i - ((i >>> 1) & 0x55555555); + i = (i & 0x33333333) + ((i >>> 2) & 0x33333333); + i = (i + (i >>> 4)) & 0x0f0f0f0f; + i = i + (i >>> 8); + i = i + (i >>> 16); + return i & 0x3f; } ``` diff --git a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution.cpp b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution.cpp index d401c1a03ad8d..269f270fa1f4a 100644 --- a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution.cpp +++ b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution.cpp @@ -1,28 +1,25 @@ -using ll = long long; - class Solution { public: - vector f; - vector power; - int n; - long long minimumTime(vector& power) { - n = power.size(); - f.assign(1 << n, -1); - this->power = power; - return dfs(0); + int n = power.size(); + long long f[1 << n]; + memset(f, -1, sizeof(f)); + auto dfs = [&](auto&& dfs, int mask) -> long long { + if (mask == 0) { + return 0; + } + if (f[mask] != -1) { + return f[mask]; + } + f[mask] = LLONG_MAX; + int gain = 1 + (n - __builtin_popcount(mask)); + for (int i = 0; i < n; ++i) { + if (mask >> i & 1) { + f[mask] = min(f[mask], dfs(dfs, mask ^ (1 << i)) + (power[i] + gain - 1) / gain); + } + } + return f[mask]; + }; + return dfs(dfs, (1 << n) - 1); } - - ll dfs(int mask) { - if (f[mask] != -1) return f[mask]; - int cnt = __builtin_popcount(mask); - if (cnt == n) return 0; - ll ans = LONG_MAX; - for (int i = 0; i < n; ++i) { - if ((mask >> i) & 1) continue; - ans = min(ans, dfs(mask | 1 << i) + (power[i] + cnt) / (cnt + 1)); - } - f[mask] = ans; - return ans; - } -}; \ No newline at end of file +}; diff --git a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution.go b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution.go index e7d7c93151773..5212581095404 100644 --- a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution.go +++ b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution.go @@ -6,22 +6,20 @@ func minimumTime(power []int) int64 { } var dfs func(mask int) int64 dfs = func(mask int) int64 { + if mask == 0 { + return 0 + } if f[mask] != -1 { return f[mask] } - cnt := bits.OnesCount(uint(mask)) - if cnt == n { - return 0 - } - var ans int64 = math.MaxInt64 - for i, v := range power { - if (mask >> i & 1) == 1 { - continue + f[mask] = 1e18 + gain := 1 + (n - bits.OnesCount(uint(mask))) + for i, x := range power { + if mask>>i&1 == 1 { + f[mask] = min(f[mask], dfs(mask^(1<> i) & 1) == 1) { - continue; + if ((mask >> i & 1) == 1) { + f[mask] = Math.min(f[mask], dfs(mask ^ 1 << i) + (power[i] + gain - 1) / gain); } - ans = Math.min(ans, dfs(mask | 1 << i) + (power[i] + cnt) / (cnt + 1)); } - f[mask] = ans; - return ans; + return f[mask]; } -} \ No newline at end of file +} diff --git a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution.py b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution.py index 205a1728130d1..c015d4e477467 100644 --- a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution.py +++ b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution.py @@ -1,15 +1,15 @@ class Solution: def minimumTime(self, power: List[int]) -> int: @cache - def dfs(mask): - cnt = mask.bit_count() - if cnt == len(power): + def dfs(mask: int) -> int: + if mask == 0: return 0 ans = inf - for i, v in enumerate(power): - if mask & (1 << i): - continue - ans = min(ans, dfs(mask | 1 << i) + (v + cnt) // (cnt + 1)) + gain = 1 + (n - mask.bit_count()) + for i, x in enumerate(power): + if mask >> i & 1: + ans = min(ans, dfs(mask ^ (1 << i)) + (x + gain - 1) // gain) return ans - return dfs(0) + n = len(power) + return dfs((1 << n) - 1) diff --git a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution.ts b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution.ts index 8ab0060bb97d8..2b12e57ba46e1 100644 --- a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution.ts +++ b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution.ts @@ -1,33 +1,30 @@ function minimumTime(power: number[]): number { const n = power.length; - const f = new Array(1 << n).fill(-1); - function dfs(mask) { - if (f[mask] != -1) { - return f[mask]; - } - const cnt = bitCount(mask); - if (cnt == n) { + const f: number[] = Array(1 << n).fill(-1); + const dfs = (mask: number): number => { + if (mask === 0) { return 0; } - let ans = Infinity; + if (f[mask] !== -1) { + return f[mask]; + } + f[mask] = Infinity; + const gain = 1 + (n - bitCount(mask)); for (let i = 0; i < n; ++i) { if ((mask >> i) & 1) { - continue; + f[mask] = Math.min(f[mask], dfs(mask ^ (1 << i)) + Math.ceil(power[i] / gain)); } - ans = Math.min(ans, dfs(mask | (1 << i)) + Math.ceil(power[i] / (cnt + 1))); } - f[mask] = ans; - return ans; - } - return dfs(0); + return f[mask]; + }; + return dfs((1 << n) - 1); } -function bitCount(x) { - let cnt = 0; - for (let i = 0; i < 32; ++i) { - if ((x >> i) & 1) { - ++cnt; - } - } - return cnt; +function bitCount(i: number): number { + i = i - ((i >>> 1) & 0x55555555); + i = (i & 0x33333333) + ((i >>> 2) & 0x33333333); + i = (i + (i >>> 4)) & 0x0f0f0f0f; + i = i + (i >>> 8); + i = i + (i >>> 16); + return i & 0x3f; } diff --git a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution2.cpp b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution2.cpp index 5c874a7ea9ff0..62e91fc21eb4a 100644 --- a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution2.cpp +++ b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution2.cpp @@ -2,16 +2,17 @@ class Solution { public: long long minimumTime(vector& power) { int n = power.size(); - vector dp(1 << n, LONG_MAX); - dp[0] = 0; + long long f[1 << n]; + memset(f, 0x3f, sizeof(f)); + f[0] = 0; for (int mask = 1; mask < 1 << n; ++mask) { - int cnt = __builtin_popcount(mask); + int gain = __builtin_popcount(mask); for (int i = 0; i < n; ++i) { - if ((mask >> i) & 1) { - dp[mask] = min(dp[mask], dp[mask ^ (1 << i)] + (power[i] + cnt - 1) / cnt); + if (mask >> i & 1) { + f[mask] = min(f[mask], f[mask ^ (1 << i)] + (power[i] + gain - 1) / gain); } } } - return dp[(1 << n) - 1]; + return f[(1 << n) - 1]; } -}; \ No newline at end of file +}; diff --git a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution2.go b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution2.go index 3dc312425acd6..382f63e39bffe 100644 --- a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution2.go +++ b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution2.go @@ -1,17 +1,17 @@ func minimumTime(power []int) int64 { n := len(power) - dp := make([]int64, 1<> i) & 1) == 1 { - dp[mask] = min(dp[mask], dp[mask^(1<>i&1 == 1 { + f[mask] = min(f[mask], f[mask^(1<> i) & 1) == 1) { - dp[mask] = Math.min(dp[mask], dp[mask ^ (1 << i)] + (power[i] + cnt - 1) / cnt); + if ((mask >> i & 1) == 1) { + f[mask] = Math.min(f[mask], f[mask ^ 1 << i] + (power[i] + gain - 1) / gain); } } } - return dp[(1 << n) - 1]; + return f[(1 << n) - 1]; } -} \ No newline at end of file +} diff --git a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution2.py b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution2.py index 56b4872e6e9b2..7b61046ef4353 100644 --- a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution2.py +++ b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution2.py @@ -1,11 +1,11 @@ class Solution: def minimumTime(self, power: List[int]) -> int: n = len(power) - dp = [inf] * (1 << n) - dp[0] = 0 + f = [inf] * (1 << n) + f[0] = 0 for mask in range(1, 1 << n): - cnt = mask.bit_count() - for i, v in enumerate(power): - if (mask >> i) & 1: - dp[mask] = min(dp[mask], dp[mask ^ (1 << i)] + (v + cnt - 1) // cnt) - return dp[-1] + gain = mask.bit_count() + for i, x in enumerate(power): + if mask >> i & 1: + f[mask] = min(f[mask], f[mask ^ (1 << i)] + (x + gain - 1) // gain) + return f[-1] diff --git a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution2.ts b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution2.ts index 7b6084915b180..c7c4bbcbbc5c8 100644 --- a/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution2.ts +++ b/solution/2400-2499/2403.Minimum Time to Kill All Monsters/Solution2.ts @@ -1,24 +1,23 @@ function minimumTime(power: number[]): number { const n = power.length; - const dp = new Array(1 << n).fill(Infinity); - dp[0] = 0; + const f: number[] = Array(1 << n).fill(Infinity); + f[0] = 0; for (let mask = 1; mask < 1 << n; ++mask) { - const cnt = bitCount(mask); + const gain = bitCount(mask); for (let i = 0; i < n; ++i) { if ((mask >> i) & 1) { - dp[mask] = Math.min(dp[mask], dp[mask ^ (1 << i)] + Math.ceil(power[i] / cnt)); + f[mask] = Math.min(f[mask], f[mask ^ (1 << i)] + Math.ceil(power[i] / gain)); } } } - return dp[dp.length - 1]; + return f.at(-1)!; } -function bitCount(x) { - let cnt = 0; - for (let i = 0; i < 32; ++i) { - if ((x >> i) & 1) { - ++cnt; - } - } - return cnt; +function bitCount(i: number): number { + i = i - ((i >>> 1) & 0x55555555); + i = (i & 0x33333333) + ((i >>> 2) & 0x33333333); + i = (i + (i >>> 4)) & 0x0f0f0f0f; + i = i + (i >>> 8); + i = i + (i >>> 16); + return i & 0x3f; }