72
72
73
73
<!-- solution:start -->
74
74
75
- ### 方法一
75
+ ### 方法一:状态压缩 + 记忆化搜索
76
+
77
+ 我们注意到,题目中物品的种类 $n \leq 6$,而每种物品需要购买的数量不超过 $10$,我们可以用 $4$ 个二进制位来表示每种物品需要购买的数量,这样,我们只需要最多 $6 \times 4 = 24$ 个二进制位来表示整个购物清单。
78
+
79
+ 我们首先将购物清单 $\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$。
80
+
81
+ 然后,我们设计一个函数 $\text{dfs}(cur)$,表示当前购物清单的状态为 $\text{cur}$ 时,我们需要花费的最少金额。那么答案即为 $\text{dfs}(\text{mask})$。
82
+
83
+ 函数 $\text{dfs}(cur)$ 的计算方法如下:
84
+
85
+ - 我们首先计算当前购物清单 $\text{cur}$ 不使用大礼包时的花费,记为 $\text{ans}$。
86
+ - 然后,我们遍历每一个大礼包 $\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}))$。
87
+ - 最后,返回 $\text{ans}$。
88
+
89
+ 为了避免重复计算,我们使用一个哈希表 $\text{f}$ 记录每一个状态 $\text{cur}$ 对应的最少花费。
90
+
91
+ 时间复杂度 $O(n \times k \times m^n)$,其中 $n$ 表示物品的种类,而 $k$ 和 $m$ 分别表示大礼包的数量以及每种物品的最大需求量。空间复杂度 $O(n \times m^n)$。
76
92
77
93
<!-- tabs:start -->
78
94
@@ -83,55 +99,72 @@ class Solution:
83
99
def shoppingOffers (
84
100
self , price : List[int ], special : List[List[int ]], needs : List[int ]
85
101
) -> int :
86
- def total (price , needs ):
87
- return sum (price[i] * needs[i] for i in range (len (needs)))
88
-
89
- ans = total(price, needs)
90
- t = []
91
- for offer in special:
92
- t.clear()
93
- for j in range (len (needs)):
94
- if offer[j] > needs[j]:
95
- t.clear()
96
- break
97
- t.append(needs[j] - offer[j])
98
- if t:
99
- ans = min (ans, offer[- 1 ] + self .shoppingOffers(price, special, t))
100
- return ans
102
+ @cache
103
+ def dfs (cur : int ) -> int :
104
+ ans = sum (p * (cur >> (i * bits) & 0x F ) for i, p in enumerate (price))
105
+ for offer in special:
106
+ nxt = cur
107
+ for j in range (len (needs)):
108
+ if (cur >> (j * bits) & 0x F ) < offer[j]:
109
+ break
110
+ nxt -= offer[j] << (j * bits)
111
+ else :
112
+ ans = min (ans, offer[- 1 ] + dfs(nxt))
113
+ return ans
114
+
115
+ bits, mask = 4 , 0
116
+ for i, need in enumerate (needs):
117
+ mask |= need << i * bits
118
+ return dfs(mask)
101
119
```
102
120
103
121
#### Java
104
122
105
123
``` java
106
124
class Solution {
125
+ private final int bits = 4 ;
126
+ private int n;
127
+ private List<Integer > price;
128
+ private List<List<Integer > > special;
129
+ private Map<Integer , Integer > f = new HashMap<> ();
130
+
107
131
public int shoppingOffers (
108
132
List<Integer > price , List<List<Integer > > special , List<Integer > needs ) {
109
- int ans = total(price, needs);
110
- List<Integer > t = new ArrayList<> ();
133
+ n = needs. size();
134
+ this . price = price;
135
+ this . special = special;
136
+ int mask = 0 ;
137
+ for (int i = 0 ; i < n; ++ i) {
138
+ mask |= needs. get(i) << (i * bits);
139
+ }
140
+ return dfs(mask);
141
+ }
142
+
143
+ private int dfs (int cur ) {
144
+ if (f. containsKey(cur)) {
145
+ return f. get(cur);
146
+ }
147
+ int ans = 0 ;
148
+ for (int i = 0 ; i < n; ++ i) {
149
+ ans += price. get(i) * (cur >> (i * bits) & 0xf );
150
+ }
111
151
for (List<Integer > offer : special) {
112
- t. clear();
113
- for (int j = 0 ; j < needs. size(); ++ j) {
114
- if (offer. get(j) > needs. get(j)) {
115
- t. clear();
152
+ int nxt = cur;
153
+ boolean ok = true ;
154
+ for (int j = 0 ; j < n; ++ j) {
155
+ if ((cur >> (j * bits) & 0xf ) < offer. get(j)) {
156
+ ok = false ;
116
157
break ;
117
158
}
118
- t . add(needs . get(j) - offer. get(j));
159
+ nxt -= offer. get(j) << (j * bits );
119
160
}
120
- if (! t. isEmpty()) {
121
- ans = Math . min(
122
- ans, offer. get(offer. size() - 1 ) + shoppingOffers(price, special, t));
161
+ if (ok) {
162
+ ans = Math . min(ans, offer. get(n) + dfs(nxt));
123
163
}
124
164
}
165
+ f. put(cur, ans);
125
166
return ans;
126
167
}
127
-
128
- private int total (List<Integer > price , List<Integer > needs ) {
129
- int s = 0 ;
130
- for (int i = 0 ; i < price. size(); ++ i) {
131
- s += price. get(i) * needs. get(i);
132
- }
133
- return s;
134
- }
135
168
}
136
169
```
137
170
@@ -141,26 +174,39 @@ class Solution {
141
174
class Solution {
142
175
public:
143
176
int shoppingOffers(vector<int >& price, vector<vector<int >>& special, vector<int >& needs) {
144
- int ans = total(price, needs);
145
- vector<int > t;
146
- for (auto& offer : special) {
147
- t.clear();
148
- for (int j = 0; j < needs.size(); ++j) {
149
- if (offer[ j] > needs[ j] ) {
150
- t.clear();
151
- break;
177
+ const int bits = 4;
178
+ int n = needs.size();
179
+ unordered_map<int, int> f;
180
+ int mask = 0;
181
+ for (int i = 0; i < n; ++i) {
182
+ mask |= needs[ i] << (i * bits);
183
+ }
184
+ function<int(int)> dfs = [ &] (int cur) {
185
+ if (f.contains(cur)) {
186
+ return f[ cur] ;
187
+ }
188
+ int ans = 0;
189
+ for (int i = 0; i < n; ++i) {
190
+ ans += price[ i] * ((cur >> (i * bits)) & 0xf);
191
+ }
192
+ for (const auto& offer : special) {
193
+ int nxt = cur;
194
+ bool ok = true;
195
+ for (int j = 0; j < n; ++j) {
196
+ if (((cur >> (j * bits)) & 0xf) < offer[ j] ) {
197
+ ok = false;
198
+ break;
199
+ }
200
+ nxt -= offer[ j] << (j * bits);
201
+ }
202
+ if (ok) {
203
+ ans = min(ans, offer[ n] + dfs(nxt));
152
204
}
153
- t.push_back(needs[ j] - offer[ j] );
154
205
}
155
- if (!t.empty()) ans = min(ans, offer[ offer.size() - 1] + shoppingOffers(price, special, t));
156
- }
157
- return ans;
158
- }
159
-
160
- int total(vector<int>& price, vector<int>& needs) {
161
- int s = 0;
162
- for (int i = 0; i < price.size(); ++i) s += price[i] * needs[i];
163
- return s;
206
+ f[ cur] = ans;
207
+ return ans;
208
+ };
209
+ return dfs(mask);
164
210
}
165
211
};
166
212
```
@@ -169,37 +215,85 @@ public:
169
215
170
216
```go
171
217
func shoppingOffers(price []int, special [][]int, needs []int) int {
172
- total := func (price, needs [] int ) int {
173
- s := 0
174
- for i := 0 ; i < len (needs); i++ {
175
- s += price[i] * needs[i]
176
- }
177
- return s
218
+ const bits = 4
219
+ n := len(needs)
220
+ f := make(map[int]int)
221
+ mask := 0
222
+ for i, need := range needs {
223
+ mask |= need << (i * bits)
178
224
}
179
225
180
- min := func (a, b int ) int {
181
- if a < b {
182
- return a
226
+ var dfs func(int) int
227
+ dfs = func(cur int) int {
228
+ if v, ok := f[cur]; ok {
229
+ return v
183
230
}
184
- return b
185
- }
186
-
187
- ans := total (price, needs)
188
- var t []int
189
- for _ , offer := range special {
190
- t = t[:0 ]
191
- for j := 0 ; j < len (needs); j++ {
192
- if offer[j] > needs[j] {
193
- t = t[:0 ]
194
- break
195
- }
196
- t = append (t, needs[j]-offer[j])
231
+ ans := 0
232
+ for i := 0; i < n; i++ {
233
+ ans += price[i] * ((cur >> (i * bits)) & 0xf)
197
234
}
198
- if len (t) > 0 {
199
- ans = min (ans, offer[len (offer)-1 ]+shoppingOffers (price, special, t))
235
+ for _, offer := range special {
236
+ nxt := cur
237
+ ok := true
238
+ for j := 0; j < n; j++ {
239
+ if ((cur >> (j * bits)) & 0xf) < offer[j] {
240
+ ok = false
241
+ break
242
+ }
243
+ nxt -= offer[j] << (j * bits)
244
+ }
245
+ if ok {
246
+ ans = min(ans, offer[n]+dfs(nxt))
247
+ }
200
248
}
249
+ f[cur] = ans
250
+ return ans
201
251
}
202
- return ans
252
+
253
+ return dfs(mask)
254
+ }
255
+ ```
256
+
257
+ #### TypeScript
258
+
259
+ ``` ts
260
+ function shoppingOffers(price : number [], special : number [][], needs : number []): number {
261
+ const bits = 4 ;
262
+ const n = needs .length ;
263
+ const f: Map <number , number > = new Map ();
264
+
265
+ let mask = 0 ;
266
+ for (let i = 0 ; i < n ; i ++ ) {
267
+ mask |= needs [i ] << (i * bits );
268
+ }
269
+
270
+ const dfs = (cur : number ): number => {
271
+ if (f .has (cur )) {
272
+ return f .get (cur )! ;
273
+ }
274
+ let ans = 0 ;
275
+ for (let i = 0 ; i < n ; i ++ ) {
276
+ ans += price [i ] * ((cur >> (i * bits )) & 0xf );
277
+ }
278
+ for (const offer of special ) {
279
+ let nxt = cur ;
280
+ let ok = true ;
281
+ for (let j = 0 ; j < n ; j ++ ) {
282
+ if (((cur >> (j * bits )) & 0xf ) < offer [j ]) {
283
+ ok = false ;
284
+ break ;
285
+ }
286
+ nxt -= offer [j ] << (j * bits );
287
+ }
288
+ if (ok ) {
289
+ ans = Math .min (ans , offer [n ] + dfs (nxt ));
290
+ }
291
+ }
292
+ f .set (cur , ans );
293
+ return ans ;
294
+ };
295
+
296
+ return dfs (mask );
203
297
}
204
298
```
205
299
0 commit comments