diff --git a/solution/0600-0699/0638.Shopping Offers/README.md b/solution/0600-0699/0638.Shopping Offers/README.md index b868682141790..fd29183233542 100644 --- a/solution/0600-0699/0638.Shopping Offers/README.md +++ b/solution/0600-0699/0638.Shopping Offers/README.md @@ -72,7 +72,23 @@ tags: -### 方法一 +### 方法一:状态压缩 + 记忆化搜索 + +我们注意到,题目中物品的种类 $n \leq 6$,而每种物品需要购买的数量不超过 $10$,我们可以用 $4$ 个二进制位来表示每种物品需要购买的数量,这样,我们只需要最多 $6 \times 4 = 24$ 个二进制位来表示整个购物清单。 + +我们首先将购物清单 $\text{needs}$ 转换为一个整数 $\text{mask}$,其中第 $i$ 个物品需要购买的数量存储在 $\text{mask}$ 的第 $i \times 4$ 位到第 $(i + 1) \times 4 - 1$ 位。例如,当 $\text{needs} = [1, 2, 1]$ 时,有 $\text{mask} = 0b0001 0010 0001$。 + +然后,我们设计一个函数 $\text{dfs}(cur)$,表示当前购物清单的状态为 $\text{cur}$ 时,我们需要花费的最少金额。那么答案即为 $\text{dfs}(\text{mask})$。 + +函数 $\text{dfs}(cur)$ 的计算方法如下: + +- 我们首先计算当前购物清单 $\text{cur}$ 不使用大礼包时的花费,记为 $\text{ans}$。 +- 然后,我们遍历每一个大礼包 $\text{offer}$,如果当前购物清单 $\text{cur}$ 能够使用大礼包 $\text{offer}$,即 $\text{cur}$ 中每种物品的数量都不小于大礼包 $\text{offer}$ 中的数量,那么我们可以尝试使用这个大礼包。我们将 $\text{cur}$ 中每种物品的数量减去大礼包 $\text{offer}$ 中的数量,得到一个新的购物清单 $\text{nxt}$,然后递归计算 $\text{nxt}$ 的最少花费,并加上大礼包的价格 $\text{offer}[n]$,更新 $\text{ans}$,即 $\text{ans} = \min(\text{ans}, \text{offer}[n] + \text{dfs}(\text{nxt}))$。 +- 最后,返回 $\text{ans}$。 + +为了避免重复计算,我们使用一个哈希表 $\text{f}$ 记录每一个状态 $\text{cur}$ 对应的最少花费。 + +时间复杂度 $O(n \times k \times m^n)$,其中 $n$ 表示物品的种类,而 $k$ 和 $m$ 分别表示大礼包的数量以及每种物品的最大需求量。空间复杂度 $O(n \times m^n)$。 @@ -83,55 +99,72 @@ class Solution: def shoppingOffers( self, price: List[int], special: List[List[int]], needs: List[int] ) -> int: - def total(price, needs): - return sum(price[i] * needs[i] for i in range(len(needs))) - - ans = total(price, needs) - t = [] - for offer in special: - t.clear() - for j in range(len(needs)): - if offer[j] > needs[j]: - t.clear() - break - t.append(needs[j] - offer[j]) - if t: - ans = min(ans, offer[-1] + self.shoppingOffers(price, special, t)) - return ans + @cache + def dfs(cur: int) -> int: + ans = sum(p * (cur >> (i * bits) & 0xF) for i, p in enumerate(price)) + for offer in special: + nxt = cur + for j in range(len(needs)): + if (cur >> (j * bits) & 0xF) < offer[j]: + break + nxt -= offer[j] << (j * bits) + else: + ans = min(ans, offer[-1] + dfs(nxt)) + return ans + + bits, mask = 4, 0 + for i, need in enumerate(needs): + mask |= need << i * bits + return dfs(mask) ``` #### Java ```java class Solution { + private final int bits = 4; + private int n; + private List price; + private List> special; + private Map f = new HashMap<>(); + public int shoppingOffers( List price, List> special, List needs) { - int ans = total(price, needs); - List t = new ArrayList<>(); + n = needs.size(); + this.price = price; + this.special = special; + int mask = 0; + for (int i = 0; i < n; ++i) { + mask |= needs.get(i) << (i * bits); + } + return dfs(mask); + } + + private int dfs(int cur) { + if (f.containsKey(cur)) { + return f.get(cur); + } + int ans = 0; + for (int i = 0; i < n; ++i) { + ans += price.get(i) * (cur >> (i * bits) & 0xf); + } for (List offer : special) { - t.clear(); - for (int j = 0; j < needs.size(); ++j) { - if (offer.get(j) > needs.get(j)) { - t.clear(); + int nxt = cur; + boolean ok = true; + for (int j = 0; j < n; ++j) { + if ((cur >> (j * bits) & 0xf) < offer.get(j)) { + ok = false; break; } - t.add(needs.get(j) - offer.get(j)); + nxt -= offer.get(j) << (j * bits); } - if (!t.isEmpty()) { - ans = Math.min( - ans, offer.get(offer.size() - 1) + shoppingOffers(price, special, t)); + if (ok) { + ans = Math.min(ans, offer.get(n) + dfs(nxt)); } } + f.put(cur, ans); return ans; } - - private int total(List price, List needs) { - int s = 0; - for (int i = 0; i < price.size(); ++i) { - s += price.get(i) * needs.get(i); - } - return s; - } } ``` @@ -141,26 +174,39 @@ class Solution { class Solution { public: int shoppingOffers(vector& price, vector>& special, vector& needs) { - int ans = total(price, needs); - vector t; - for (auto& offer : special) { - t.clear(); - for (int j = 0; j < needs.size(); ++j) { - if (offer[j] > needs[j]) { - t.clear(); - break; + const int bits = 4; + int n = needs.size(); + unordered_map f; + int mask = 0; + for (int i = 0; i < n; ++i) { + mask |= needs[i] << (i * bits); + } + function dfs = [&](int cur) { + if (f.contains(cur)) { + return f[cur]; + } + int ans = 0; + for (int i = 0; i < n; ++i) { + ans += price[i] * ((cur >> (i * bits)) & 0xf); + } + for (const auto& offer : special) { + int nxt = cur; + bool ok = true; + for (int j = 0; j < n; ++j) { + if (((cur >> (j * bits)) & 0xf) < offer[j]) { + ok = false; + break; + } + nxt -= offer[j] << (j * bits); + } + if (ok) { + ans = min(ans, offer[n] + dfs(nxt)); } - t.push_back(needs[j] - offer[j]); } - if (!t.empty()) ans = min(ans, offer[offer.size() - 1] + shoppingOffers(price, special, t)); - } - return ans; - } - - int total(vector& price, vector& needs) { - int s = 0; - for (int i = 0; i < price.size(); ++i) s += price[i] * needs[i]; - return s; + f[cur] = ans; + return ans; + }; + return dfs(mask); } }; ``` @@ -169,37 +215,85 @@ public: ```go func shoppingOffers(price []int, special [][]int, needs []int) int { - total := func(price, needs []int) int { - s := 0 - for i := 0; i < len(needs); i++ { - s += price[i] * needs[i] - } - return s + const bits = 4 + n := len(needs) + f := make(map[int]int) + mask := 0 + for i, need := range needs { + mask |= need << (i * bits) } - min := func(a, b int) int { - if a < b { - return a + var dfs func(int) int + dfs = func(cur int) int { + if v, ok := f[cur]; ok { + return v } - return b - } - - ans := total(price, needs) - var t []int - for _, offer := range special { - t = t[:0] - for j := 0; j < len(needs); j++ { - if offer[j] > needs[j] { - t = t[:0] - break - } - t = append(t, needs[j]-offer[j]) + ans := 0 + for i := 0; i < n; i++ { + ans += price[i] * ((cur >> (i * bits)) & 0xf) } - if len(t) > 0 { - ans = min(ans, offer[len(offer)-1]+shoppingOffers(price, special, t)) + for _, offer := range special { + nxt := cur + ok := true + for j := 0; j < n; j++ { + if ((cur >> (j * bits)) & 0xf) < offer[j] { + ok = false + break + } + nxt -= offer[j] << (j * bits) + } + if ok { + ans = min(ans, offer[n]+dfs(nxt)) + } } + f[cur] = ans + return ans } - return ans + + return dfs(mask) +} +``` + +#### TypeScript + +```ts +function shoppingOffers(price: number[], special: number[][], needs: number[]): number { + const bits = 4; + const n = needs.length; + const f: Map = new Map(); + + let mask = 0; + for (let i = 0; i < n; i++) { + mask |= needs[i] << (i * bits); + } + + const dfs = (cur: number): number => { + if (f.has(cur)) { + return f.get(cur)!; + } + let ans = 0; + for (let i = 0; i < n; i++) { + ans += price[i] * ((cur >> (i * bits)) & 0xf); + } + for (const offer of special) { + let nxt = cur; + let ok = true; + for (let j = 0; j < n; j++) { + if (((cur >> (j * bits)) & 0xf) < offer[j]) { + ok = false; + break; + } + nxt -= offer[j] << (j * bits); + } + if (ok) { + ans = Math.min(ans, offer[n] + dfs(nxt)); + } + } + f.set(cur, ans); + return ans; + }; + + return dfs(mask); } ``` diff --git a/solution/0600-0699/0638.Shopping Offers/README_EN.md b/solution/0600-0699/0638.Shopping Offers/README_EN.md index 4178b57604475..a08277e2168ce 100644 --- a/solution/0600-0699/0638.Shopping Offers/README_EN.md +++ b/solution/0600-0699/0638.Shopping Offers/README_EN.md @@ -70,7 +70,23 @@ You cannot add more items, though only $9 for 2A ,2B and 1C. -### Solution 1 +### Solution 1: State Compression + Memoization Search + +We notice that the number of types of items $n \leq 6$ in the problem, and the quantity of each item needed does not exceed $10$. We can use $4$ binary bits to represent the quantity of each item needed. Thus, we only need at most $6 \times 4 = 24$ binary bits to represent the entire shopping list. + +First, we convert the shopping list $\text{needs}$ into an integer $\text{mask}$, where the quantity of the $i$-th item needed is stored in the $i \times 4$ to $(i + 1) \times 4 - 1$ bits of $\text{mask}$. For example, when $\text{needs} = [1, 2, 1]$, we have $\text{mask} = 0b0001 0010 0001$. + +Then, we design a function $\text{dfs}(cur)$, representing the minimum amount of money we need to spend when the current state of the shopping list is $\text{cur}$. Therefore, the answer is $\text{dfs}(\text{mask})$. + +The calculation method of the function $\text{dfs}(cur)$ is as follows: + +- First, we calculate the cost of the current shopping list $\text{cur}$ without using any bundles, denoted as $\text{ans}$. +- Then, we iterate through each bundle $\text{offer}$. If the current shopping list $\text{cur}$ can use the bundle $\text{offer}$, i.e., the quantity of each item in $\text{cur}$ is not less than that in the bundle $\text{offer}$, then we can try to use this bundle. We subtract the quantity of each item in the bundle $\text{offer}$ from $\text{cur}$, obtaining a new shopping list $\text{nxt}$, then recursively calculate the minimum cost of $\text{nxt}$ and add the price of the bundle $\text{offer}[n]$, updating $\text{ans}$, i.e., $\text{ans} = \min(\text{ans}, \text{offer}[n] + \text{dfs}(\text{nxt}))$. +- Finally, return $\text{ans}$. + +To avoid repeated calculations, we use a hash table $\text{f}$ to record the minimum cost corresponding to each state $\text{cur}$. + +The time complexity is $O(n \times k \times m^n)$, where $n$ represents the types of items, and $k$ and $m$ respectively represent the number of bundles and the maximum demand for each type of item. The space complexity is $O(n \times m^n)$. @@ -81,55 +97,72 @@ class Solution: def shoppingOffers( self, price: List[int], special: List[List[int]], needs: List[int] ) -> int: - def total(price, needs): - return sum(price[i] * needs[i] for i in range(len(needs))) - - ans = total(price, needs) - t = [] - for offer in special: - t.clear() - for j in range(len(needs)): - if offer[j] > needs[j]: - t.clear() - break - t.append(needs[j] - offer[j]) - if t: - ans = min(ans, offer[-1] + self.shoppingOffers(price, special, t)) - return ans + @cache + def dfs(cur: int) -> int: + ans = sum(p * (cur >> (i * bits) & 0xF) for i, p in enumerate(price)) + for offer in special: + nxt = cur + for j in range(len(needs)): + if (cur >> (j * bits) & 0xF) < offer[j]: + break + nxt -= offer[j] << (j * bits) + else: + ans = min(ans, offer[-1] + dfs(nxt)) + return ans + + bits, mask = 4, 0 + for i, need in enumerate(needs): + mask |= need << i * bits + return dfs(mask) ``` #### Java ```java class Solution { + private final int bits = 4; + private int n; + private List price; + private List> special; + private Map f = new HashMap<>(); + public int shoppingOffers( List price, List> special, List needs) { - int ans = total(price, needs); - List t = new ArrayList<>(); + n = needs.size(); + this.price = price; + this.special = special; + int mask = 0; + for (int i = 0; i < n; ++i) { + mask |= needs.get(i) << (i * bits); + } + return dfs(mask); + } + + private int dfs(int cur) { + if (f.containsKey(cur)) { + return f.get(cur); + } + int ans = 0; + for (int i = 0; i < n; ++i) { + ans += price.get(i) * (cur >> (i * bits) & 0xf); + } for (List offer : special) { - t.clear(); - for (int j = 0; j < needs.size(); ++j) { - if (offer.get(j) > needs.get(j)) { - t.clear(); + int nxt = cur; + boolean ok = true; + for (int j = 0; j < n; ++j) { + if ((cur >> (j * bits) & 0xf) < offer.get(j)) { + ok = false; break; } - t.add(needs.get(j) - offer.get(j)); + nxt -= offer.get(j) << (j * bits); } - if (!t.isEmpty()) { - ans = Math.min( - ans, offer.get(offer.size() - 1) + shoppingOffers(price, special, t)); + if (ok) { + ans = Math.min(ans, offer.get(n) + dfs(nxt)); } } + f.put(cur, ans); return ans; } - - private int total(List price, List needs) { - int s = 0; - for (int i = 0; i < price.size(); ++i) { - s += price.get(i) * needs.get(i); - } - return s; - } } ``` @@ -139,26 +172,39 @@ class Solution { class Solution { public: int shoppingOffers(vector& price, vector>& special, vector& needs) { - int ans = total(price, needs); - vector t; - for (auto& offer : special) { - t.clear(); - for (int j = 0; j < needs.size(); ++j) { - if (offer[j] > needs[j]) { - t.clear(); - break; + const int bits = 4; + int n = needs.size(); + unordered_map f; + int mask = 0; + for (int i = 0; i < n; ++i) { + mask |= needs[i] << (i * bits); + } + function dfs = [&](int cur) { + if (f.contains(cur)) { + return f[cur]; + } + int ans = 0; + for (int i = 0; i < n; ++i) { + ans += price[i] * ((cur >> (i * bits)) & 0xf); + } + for (const auto& offer : special) { + int nxt = cur; + bool ok = true; + for (int j = 0; j < n; ++j) { + if (((cur >> (j * bits)) & 0xf) < offer[j]) { + ok = false; + break; + } + nxt -= offer[j] << (j * bits); + } + if (ok) { + ans = min(ans, offer[n] + dfs(nxt)); } - t.push_back(needs[j] - offer[j]); } - if (!t.empty()) ans = min(ans, offer[offer.size() - 1] + shoppingOffers(price, special, t)); - } - return ans; - } - - int total(vector& price, vector& needs) { - int s = 0; - for (int i = 0; i < price.size(); ++i) s += price[i] * needs[i]; - return s; + f[cur] = ans; + return ans; + }; + return dfs(mask); } }; ``` @@ -167,37 +213,85 @@ public: ```go func shoppingOffers(price []int, special [][]int, needs []int) int { - total := func(price, needs []int) int { - s := 0 - for i := 0; i < len(needs); i++ { - s += price[i] * needs[i] - } - return s + const bits = 4 + n := len(needs) + f := make(map[int]int) + mask := 0 + for i, need := range needs { + mask |= need << (i * bits) } - min := func(a, b int) int { - if a < b { - return a + var dfs func(int) int + dfs = func(cur int) int { + if v, ok := f[cur]; ok { + return v } - return b - } - - ans := total(price, needs) - var t []int - for _, offer := range special { - t = t[:0] - for j := 0; j < len(needs); j++ { - if offer[j] > needs[j] { - t = t[:0] - break - } - t = append(t, needs[j]-offer[j]) + ans := 0 + for i := 0; i < n; i++ { + ans += price[i] * ((cur >> (i * bits)) & 0xf) } - if len(t) > 0 { - ans = min(ans, offer[len(offer)-1]+shoppingOffers(price, special, t)) + for _, offer := range special { + nxt := cur + ok := true + for j := 0; j < n; j++ { + if ((cur >> (j * bits)) & 0xf) < offer[j] { + ok = false + break + } + nxt -= offer[j] << (j * bits) + } + if ok { + ans = min(ans, offer[n]+dfs(nxt)) + } } + f[cur] = ans + return ans } - return ans + + return dfs(mask) +} +``` + +#### TypeScript + +```ts +function shoppingOffers(price: number[], special: number[][], needs: number[]): number { + const bits = 4; + const n = needs.length; + const f: Map = new Map(); + + let mask = 0; + for (let i = 0; i < n; i++) { + mask |= needs[i] << (i * bits); + } + + const dfs = (cur: number): number => { + if (f.has(cur)) { + return f.get(cur)!; + } + let ans = 0; + for (let i = 0; i < n; i++) { + ans += price[i] * ((cur >> (i * bits)) & 0xf); + } + for (const offer of special) { + let nxt = cur; + let ok = true; + for (let j = 0; j < n; j++) { + if (((cur >> (j * bits)) & 0xf) < offer[j]) { + ok = false; + break; + } + nxt -= offer[j] << (j * bits); + } + if (ok) { + ans = Math.min(ans, offer[n] + dfs(nxt)); + } + } + f.set(cur, ans); + return ans; + }; + + return dfs(mask); } ``` diff --git a/solution/0600-0699/0638.Shopping Offers/Solution.cpp b/solution/0600-0699/0638.Shopping Offers/Solution.cpp index cf1eeb13313ad..6bca937c9bd59 100644 --- a/solution/0600-0699/0638.Shopping Offers/Solution.cpp +++ b/solution/0600-0699/0638.Shopping Offers/Solution.cpp @@ -1,25 +1,38 @@ class Solution { public: int shoppingOffers(vector& price, vector>& special, vector& needs) { - int ans = total(price, needs); - vector t; - for (auto& offer : special) { - t.clear(); - for (int j = 0; j < needs.size(); ++j) { - if (offer[j] > needs[j]) { - t.clear(); - break; + const int bits = 4; + int n = needs.size(); + unordered_map f; + int mask = 0; + for (int i = 0; i < n; ++i) { + mask |= needs[i] << (i * bits); + } + function dfs = [&](int cur) { + if (f.contains(cur)) { + return f[cur]; + } + int ans = 0; + for (int i = 0; i < n; ++i) { + ans += price[i] * ((cur >> (i * bits)) & 0xf); + } + for (const auto& offer : special) { + int nxt = cur; + bool ok = true; + for (int j = 0; j < n; ++j) { + if (((cur >> (j * bits)) & 0xf) < offer[j]) { + ok = false; + break; + } + nxt -= offer[j] << (j * bits); + } + if (ok) { + ans = min(ans, offer[n] + dfs(nxt)); } - t.push_back(needs[j] - offer[j]); } - if (!t.empty()) ans = min(ans, offer[offer.size() - 1] + shoppingOffers(price, special, t)); - } - return ans; - } - - int total(vector& price, vector& needs) { - int s = 0; - for (int i = 0; i < price.size(); ++i) s += price[i] * needs[i]; - return s; + f[cur] = ans; + return ans; + }; + return dfs(mask); } }; \ No newline at end of file diff --git a/solution/0600-0699/0638.Shopping Offers/Solution.go b/solution/0600-0699/0638.Shopping Offers/Solution.go index 489503d78ecd9..6e071fdbe9737 100644 --- a/solution/0600-0699/0638.Shopping Offers/Solution.go +++ b/solution/0600-0699/0638.Shopping Offers/Solution.go @@ -1,33 +1,38 @@ func shoppingOffers(price []int, special [][]int, needs []int) int { - total := func(price, needs []int) int { - s := 0 - for i := 0; i < len(needs); i++ { - s += price[i] * needs[i] - } - return s + const bits = 4 + n := len(needs) + f := make(map[int]int) + mask := 0 + for i, need := range needs { + mask |= need << (i * bits) } - min := func(a, b int) int { - if a < b { - return a + var dfs func(int) int + dfs = func(cur int) int { + if v, ok := f[cur]; ok { + return v } - return b - } - - ans := total(price, needs) - var t []int - for _, offer := range special { - t = t[:0] - for j := 0; j < len(needs); j++ { - if offer[j] > needs[j] { - t = t[:0] - break - } - t = append(t, needs[j]-offer[j]) + ans := 0 + for i := 0; i < n; i++ { + ans += price[i] * ((cur >> (i * bits)) & 0xf) } - if len(t) > 0 { - ans = min(ans, offer[len(offer)-1]+shoppingOffers(price, special, t)) + for _, offer := range special { + nxt := cur + ok := true + for j := 0; j < n; j++ { + if ((cur >> (j * bits)) & 0xf) < offer[j] { + ok = false + break + } + nxt -= offer[j] << (j * bits) + } + if ok { + ans = min(ans, offer[n]+dfs(nxt)) + } } + f[cur] = ans + return ans } - return ans + + return dfs(mask) } \ No newline at end of file diff --git a/solution/0600-0699/0638.Shopping Offers/Solution.java b/solution/0600-0699/0638.Shopping Offers/Solution.java index 2f0058b2a4d1c..ebf634c0e3390 100644 --- a/solution/0600-0699/0638.Shopping Offers/Solution.java +++ b/solution/0600-0699/0638.Shopping Offers/Solution.java @@ -1,30 +1,45 @@ class Solution { + private final int bits = 4; + private int n; + private List price; + private List> special; + private Map f = new HashMap<>(); + public int shoppingOffers( List price, List> special, List needs) { - int ans = total(price, needs); - List t = new ArrayList<>(); + n = needs.size(); + this.price = price; + this.special = special; + int mask = 0; + for (int i = 0; i < n; ++i) { + mask |= needs.get(i) << (i * bits); + } + return dfs(mask); + } + + private int dfs(int cur) { + if (f.containsKey(cur)) { + return f.get(cur); + } + int ans = 0; + for (int i = 0; i < n; ++i) { + ans += price.get(i) * (cur >> (i * bits) & 0xf); + } for (List offer : special) { - t.clear(); - for (int j = 0; j < needs.size(); ++j) { - if (offer.get(j) > needs.get(j)) { - t.clear(); + int nxt = cur; + boolean ok = true; + for (int j = 0; j < n; ++j) { + if ((cur >> (j * bits) & 0xf) < offer.get(j)) { + ok = false; break; } - t.add(needs.get(j) - offer.get(j)); + nxt -= offer.get(j) << (j * bits); } - if (!t.isEmpty()) { - ans = Math.min( - ans, offer.get(offer.size() - 1) + shoppingOffers(price, special, t)); + if (ok) { + ans = Math.min(ans, offer.get(n) + dfs(nxt)); } } + f.put(cur, ans); return ans; } - - private int total(List price, List needs) { - int s = 0; - for (int i = 0; i < price.size(); ++i) { - s += price.get(i) * needs.get(i); - } - return s; - } } \ No newline at end of file diff --git a/solution/0600-0699/0638.Shopping Offers/Solution.py b/solution/0600-0699/0638.Shopping Offers/Solution.py index f822cdd5cde18..c06758afe0e11 100644 --- a/solution/0600-0699/0638.Shopping Offers/Solution.py +++ b/solution/0600-0699/0638.Shopping Offers/Solution.py @@ -2,18 +2,20 @@ class Solution: def shoppingOffers( self, price: List[int], special: List[List[int]], needs: List[int] ) -> int: - def total(price, needs): - return sum(price[i] * needs[i] for i in range(len(needs))) + @cache + def dfs(cur: int) -> int: + ans = sum(p * (cur >> (i * bits) & 0xF) for i, p in enumerate(price)) + for offer in special: + nxt = cur + for j in range(len(needs)): + if (cur >> (j * bits) & 0xF) < offer[j]: + break + nxt -= offer[j] << (j * bits) + else: + ans = min(ans, offer[-1] + dfs(nxt)) + return ans - ans = total(price, needs) - t = [] - for offer in special: - t.clear() - for j in range(len(needs)): - if offer[j] > needs[j]: - t.clear() - break - t.append(needs[j] - offer[j]) - if t: - ans = min(ans, offer[-1] + self.shoppingOffers(price, special, t)) - return ans + bits, mask = 4, 0 + for i, need in enumerate(needs): + mask |= need << i * bits + return dfs(mask) diff --git a/solution/0600-0699/0638.Shopping Offers/Solution.ts b/solution/0600-0699/0638.Shopping Offers/Solution.ts new file mode 100644 index 0000000000000..ad09bb7334885 --- /dev/null +++ b/solution/0600-0699/0638.Shopping Offers/Solution.ts @@ -0,0 +1,38 @@ +function shoppingOffers(price: number[], special: number[][], needs: number[]): number { + const bits = 4; + const n = needs.length; + const f: Map = new Map(); + + let mask = 0; + for (let i = 0; i < n; i++) { + mask |= needs[i] << (i * bits); + } + + const dfs = (cur: number): number => { + if (f.has(cur)) { + return f.get(cur)!; + } + let ans = 0; + for (let i = 0; i < n; i++) { + ans += price[i] * ((cur >> (i * bits)) & 0xf); + } + for (const offer of special) { + let nxt = cur; + let ok = true; + for (let j = 0; j < n; j++) { + if (((cur >> (j * bits)) & 0xf) < offer[j]) { + ok = false; + break; + } + nxt -= offer[j] << (j * bits); + } + if (ok) { + ans = Math.min(ans, offer[n] + dfs(nxt)); + } + } + f.set(cur, ans); + return ans; + }; + + return dfs(mask); +}