生活随笔
收集整理的這篇文章主要介紹了
LeetCode 638. 大礼包(无限背包DP)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1. 題目
在LeetCode商店中, 有許多在售的物品。
然而,也有一些大禮包,每個大禮包以優惠的價格捆綁銷售一組物品。
現給定每個物品的價格,每個大禮包包含物品的清單,以及待購物品清單。請輸出確切完成待購清單的最低花費。
每個大禮包的由一個數組中的一組數據描述,最后一個數字代表大禮包的價格,其他數字分別表示內含的其他種類物品的數量。
任意大禮包可無限次購買。
示例
1:
輸入
: [2,5], [[3,0,5],[1,2,10]], [3,2]
輸出
: 14
解釋
:
有A和B兩種物品,價格分別為¥
2和¥
5。
大禮包
1,你可以以¥
5的價格購買
3A和
0B。
大禮包
2, 你可以以¥
10的價格購買
1A和
2B。
你需要購買
3個A和
2個B, 所以你付了¥
10購買了
1A和
2B(大禮包
2),以及¥
4購買
2A。示例
2:
輸入
: [2,3,4], [[1,1,0,4],[2,2,1,9]], [1,2,1]
輸出
: 11
解釋
:
A,B,C的價格分別為¥
2,¥
3,¥
4.
你可以用¥
4購買
1A和
1B,也可以用¥
9購買
2A,
2B和
1C。
你需要買
1A,
2B和
1C,所以你付了¥
4買了
1A和
1B(大禮包
1),以及¥
3購買
1B, ¥
4購買
1C。
你不可以購買超出待購清單的物品,盡管購買大禮包
2更加便宜。說明
:
最多
6種物品,
100種大禮包。
每種物品,你最多只需要購買
6個。
你不可以購買超出待購清單的物品,即使更便宜。
來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/shopping-offers
著作權歸領扣網絡所有。商業轉載請聯系官方授權,非商業轉載請注明出處。
2. 解題
2.1 狀態壓縮超時解
- 思路是,把int看做買東西的個數的狀態,3個位最大是7,題目說不超過6,物品也不超過6,最多18位就可以了
- 一個int就可以存下買的物品的個數
- 最后一個例子超時,可能這個最大的狀態數太大了
class Solution {int n
;
public:int shoppingOffers(vector
<int>& price
, vector
<vector
<int>>& special
, vector
<int>& needs
) {n
= price
.size();int i
, j
, k
, target
= 0, num
, newstate
;for(i
= 0; i
< n
; ++i
)modify(target
, i
, needs
[i
]);vector
<int> dp(target
+1,INT_MAX
);dp
[0] = 0;bool lessNeed
;for(i
= 0; i
<= target
; i
++){if(dp
[i
] == INT_MAX
)continue;vector
<int> count(n
);for(j
= 0; j
< n
; ++j
)count
[j
] = getnum(i
,j
);for(j
= 0; j
< n
; ++j
){newstate
= i
;num
= count
[j
]+1;if(num
> needs
[j
])continue;modify(newstate
, j
, num
);if(newstate
<= target
)dp
[newstate
] = min(dp
[newstate
],dp
[i
]+price
[j
]);}for(k
= 0; k
< special
.size(); ++k
){newstate
= 0;lessNeed
= true;for(j
= 0; j
< n
; ++j
){num
= count
[j
]+special
[k
][j
];if(num
> needs
[j
]){lessNeed
= false;break;}modify(newstate
, j
, num
);}if(lessNeed
&& newstate
<= target
)dp
[newstate
] = min(dp
[newstate
],dp
[i
]+special
[k
][n
]);}}return dp
[target
];}void modify(int& state
, int i
, int newnum
){int bit
= 3*i
, k
= 0, newnum_bit
;for(k
= 0; k
< 3; ++k
,++bit
)state
= (~(1<<bit
))&(state
);bit
= 3*i
;for(k
= 0; k
< 3; ++k
,++bit
){newnum_bit
= (newnum
>>k
)&1;if(newnum_bit
)state
|= (1<<bit
);}}int getnum(int state
, int i
){int bit
= 3*i
+2, num
= 0;for(int k
= 0; k
< 3; ++k
,--bit
)num
= num
*2+((state
>>bit
)&1);return num
;}
};
2.2 6維動態規劃
- 把單個的也處理成大禮包,統一處理
- 不滿6個的都補滿,方便處理
class Solution {
public:int shoppingOffers(vector
<int>& price
, vector
<vector
<int>>& special
, vector
<int>& needs
) {int n
= price
.size();int i
,j
,a
,b
,c
,d
,e
,f
, money
;for(i
= 0; i
< n
; ++i
){vector
<int> bag(7,0);bag
[i
] = 1;bag
[6] = price
[i
];special
.push_back(bag
);}int dp
[11][11][11][11][11][11];memset(dp
,0x7f,sizeof(dp
));dp
[0][0][0][0][0][0] = 0;vector
<int> t(6,0);while(needs
.size() < 6)needs
.push_back(0);for(i
= 0; i
< needs
.size(); ++i
)t
[i
] = needs
[i
];for(vector
<int> & s
: special
){vector
<int> nd(6,0);money
= s
.back();for(j
= 0; j
< s
.size()-1; ++j
)nd
[j
] = s
[j
];for(a
= 0; a
<= t
[0]; ++a
)for(b
= 0; b
<= t
[1]; ++b
)for(c
= 0; c
<= t
[2]; ++c
)for(d
= 0; d
<= t
[3]; ++d
)for(e
= 0; e
<= t
[4]; ++e
)for(f
= 0; f
<= t
[5]; ++f
){if(dp
[a
][b
][c
][d
][e
][f
] != 0x7f7f7f7f && a
+nd
[0] <= needs
[0]&& b
+nd
[1] <= needs
[1] && c
+nd
[2] <= needs
[2]&& d
+nd
[3] <= needs
[3] && e
+nd
[4] <= needs
[4]&& f
+nd
[5] <= needs
[5])dp
[a
+nd
[0]][b
+nd
[1]][c
+nd
[2]][d
+nd
[3]][e
+nd
[4]][f
+nd
[5]]= min(dp
[a
+nd
[0]][b
+nd
[1]][c
+nd
[2]][d
+nd
[3]][e
+nd
[4]][f
+nd
[5]],dp
[a
][b
][c
][d
][e
][f
]+money
);}}return dp
[t
[0]][t
[1]][t
[2]][t
[3]][t
[4]][t
[5]];}
};
280 ms 18.4 MB C++
總結
以上是生活随笔為你收集整理的LeetCode 638. 大礼包(无限背包DP)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。