comments | difficulty | edit_url | tags | ||||
---|---|---|---|---|---|---|---|
true |
困难 |
|
你有一个整数数组 power
,其中 power[i]
是第 i
个怪物的力量。
你从 0
点法力值开始,每天获取 gain
点法力值,最初 gain
等于 1
。
每天,在获得 gain
点法力值后,如果你的法力值大于或等于怪物的力量,你就可以打败怪物。当你打败怪物时:
-
你的法力值会被重置为
0
,并且 -
gain
的值增加1
。
返回打败所有怪物所需的 最少 天数。
示例 1:
输入: power = [3,1,4] 输出: 4 解释: 打败所有怪物的最佳方法是: - 第 1 天: 获得 1 点法力值,现在总共拥有 1 点法力值。用尽所有法力值击杀第 2 个怪物。 - 第 2 天: 获得 2 点法力值,现在总共拥有 2 点法力值。 - 第 3 天: 获得 2 点法力值,现在总共拥有 4 点法力值。用尽所有法力值击杀第 3 个怪物。 - 第 4 天: 获得 3 点法力值,现在总共拥有 3 点法力值。 用尽所有法力值击杀第 1 个怪物。 可以证明,4 天是最少需要的天数。
示例 2:
输入: power = [1,1,4] 输出: 4 解释: 打败所有怪物的最佳方法是: - 第 1 天: 获得 1 点法力值,现在总共拥有 1 点法力值。用尽所有法力值击杀第 1 个怪物。 - 第 2 天: 获得 2 点法力值,现在总共拥有 2 点法力值。用尽所有法力值击杀第 2 个怪物。 - 第 3 天: 获得 3 点法力值,现在总共拥有 3 点法力值。 - 第 4 天: 获得 3 点法力值,现在总共拥有 6 点法力值。用尽所有法力值击杀第 3 个怪物。 可以证明,4 天是最少需要的天数。
示例 3:
输入: power = [1,2,4,9] 输出: 6 解释: 打败所有怪物的最佳方法是: - 第 1 天: 获得 1 点法力值,现在总共拥有 1 点法力值。用尽所有法力值击杀第 1 个怪物 - 第 2 天: 获得 2 点法力值,现在总共拥有 2 点法力值。用尽所有法力值击杀第 2 个怪物。 - 第 3 天: 获得 3 点法力值,现在总共拥有 3 点法力值。 - 第 4 天: 获得 3 点法力值,现在总共拥有 6 点法力值。 - 第 5 天: 获得 3 点法力值,现在总共拥有 9 点法力值。用尽所有法力值击杀第 4 个怪物。 - 第 6 天: 获得 4 点法力值,现在总共拥有 4 点法力值。用尽所有法力值击杀第 3 个怪物。 可以证明,6 天是最少需要的天数。
提示:
1 <= power.length <= 17
1 <= power[i] <= 109
我们注意带,怪物的数量最多为
我们设计一个函数
函数
- 如果
$\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}())$ ,表示当前每天可以获得的法力值。
最后,我们返回
时间复杂度
class Solution:
def minimumTime(self, power: List[int]) -> int:
@cache
def dfs(mask: int) -> int:
if mask == 0:
return 0
ans = inf
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
n = len(power)
return dfs((1 << n) - 1)
class Solution {
private int n;
private int[] power;
private Long[] f;
public long minimumTime(int[] power) {
n = power.length;
this.power = power;
f = new Long[1 << n];
return dfs((1 << n) - 1);
}
private long dfs(int mask) {
if (mask == 0) {
return 0;
}
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) {
f[mask] = Math.min(f[mask], dfs(mask ^ 1 << i) + (power[i] + gain - 1) / gain);
}
}
return f[mask];
}
}
class Solution {
public:
long long minimumTime(vector<int>& power) {
int n = power.size();
long long f[1 << n];
memset(f, -1, sizeof(f));
auto dfs = [&](this 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(mask ^ (1 << i)) + (power[i] + gain - 1) / gain);
}
}
return f[mask];
};
return dfs((1 << n) - 1);
}
};
func minimumTime(power []int) int64 {
n := len(power)
f := make([]int64, 1<<n)
for i := range f {
f[i] = -1
}
var dfs func(mask int) int64
dfs = func(mask int) int64 {
if mask == 0 {
return 0
}
if f[mask] != -1 {
return f[mask]
}
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))+int64(x+gain-1)/int64(gain))
}
}
return f[mask]
}
return dfs(1<<n - 1)
}
function minimumTime(power: number[]): number {
const n = power.length;
const f: number[] = Array(1 << n).fill(-1);
const dfs = (mask: number): number => {
if (mask === 0) {
return 0;
}
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) {
f[mask] = Math.min(f[mask], dfs(mask ^ (1 << i)) + Math.ceil(power[i] / gain));
}
}
return f[mask];
};
return dfs((1 << n) - 1);
}
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;
}
我们可以将方法一中的记忆化搜索改为动态规划,定义
我们在
最后,返回
时间复杂度
class Solution:
def minimumTime(self, power: List[int]) -> int:
n = len(power)
f = [inf] * (1 << n)
f[0] = 0
for mask in range(1, 1 << n):
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]
class Solution {
public long minimumTime(int[] power) {
int n = power.length;
long[] f = new long[1 << n];
Arrays.fill(f, Long.MAX_VALUE);
f[0] = 0;
for (int mask = 1; mask < 1 << n; ++mask) {
int gain = Integer.bitCount(mask);
for (int i = 0; i < n; ++i) {
if ((mask >> i & 1) == 1) {
f[mask] = Math.min(f[mask], f[mask ^ 1 << i] + (power[i] + gain - 1) / gain);
}
}
}
return f[(1 << n) - 1];
}
}
class Solution {
public:
long long minimumTime(vector<int>& power) {
int n = power.size();
long long f[1 << n];
memset(f, 0x3f, sizeof(f));
f[0] = 0;
for (int mask = 1; mask < 1 << n; ++mask) {
int gain = __builtin_popcount(mask);
for (int i = 0; i < n; ++i) {
if (mask >> i & 1) {
f[mask] = min(f[mask], f[mask ^ (1 << i)] + (power[i] + gain - 1) / gain);
}
}
}
return f[(1 << n) - 1];
}
};
func minimumTime(power []int) int64 {
n := len(power)
f := make([]int64, 1<<n)
for i := range f {
f[i] = 1e18
}
f[0] = 0
for mask := 1; mask < 1<<n; mask++ {
gain := bits.OnesCount(uint(mask))
for i, x := range power {
if mask>>i&1 == 1 {
f[mask] = min(f[mask], f[mask^(1<<i)]+int64(x+gain-1)/int64(gain))
}
}
}
return f[1<<n-1]
}
function minimumTime(power: number[]): number {
const n = power.length;
const f: number[] = Array(1 << n).fill(Infinity);
f[0] = 0;
for (let mask = 1; mask < 1 << n; ++mask) {
const gain = bitCount(mask);
for (let i = 0; i < n; ++i) {
if ((mask >> i) & 1) {
f[mask] = Math.min(f[mask], f[mask ^ (1 << i)] + Math.ceil(power[i] / gain));
}
}
}
return f.at(-1)!;
}
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;
}