生活随笔
收集整理的這篇文章主要介紹了
LeetCode 638. 大礼包(无限背包DP)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
1. 題目
在LeetCode商店中, 有許多在售的物品。
然而,也有一些大禮包,每個(gè)大禮包以優(yōu)惠的價(jià)格捆綁銷售一組物品。
現(xiàn)給定每個(gè)物品的價(jià)格,每個(gè)大禮包包含物品的清單,以及待購(gòu)物品清單。請(qǐng)輸出確切完成待購(gòu)清單的最低花費(fèi)。
每個(gè)大禮包的由一個(gè)數(shù)組中的一組數(shù)據(jù)描述,最后一個(gè)數(shù)字代表大禮包的價(jià)格,其他數(shù)字分別表示內(nèi)含的其他種類物品的數(shù)量。
任意大禮包可無限次購(gòu)買。
示例
1:
輸入
: [2,5], [[3,0,5],[1,2,10]], [3,2]
輸出
: 14
解釋
:
有A和B兩種物品,價(jià)格分別為¥
2和¥
5。
大禮包
1,你可以以¥
5的價(jià)格購(gòu)買
3A和
0B。
大禮包
2, 你可以以¥
10的價(jià)格購(gòu)買
1A和
2B。
你需要購(gòu)買
3個(gè)A和
2個(gè)B, 所以你付了¥
10購(gòu)買了
1A和
2B(大禮包
2),以及¥
4購(gòu)買
2A。示例
2:
輸入
: [2,3,4], [[1,1,0,4],[2,2,1,9]], [1,2,1]
輸出
: 11
解釋
:
A,B,C的價(jià)格分別為¥
2,¥
3,¥
4.
你可以用¥
4購(gòu)買
1A和
1B,也可以用¥
9購(gòu)買
2A,
2B和
1C。
你需要買
1A,
2B和
1C,所以你付了¥
4買了
1A和
1B(大禮包
1),以及¥
3購(gòu)買
1B, ¥
4購(gòu)買
1C。
你不可以購(gòu)買超出待購(gòu)清單的物品,盡管購(gòu)買大禮包
2更加便宜。說明
:
最多
6種物品,
100種大禮包。
每種物品,你最多只需要購(gòu)買
6個(gè)。
你不可以購(gòu)買超出待購(gòu)清單的物品,即使更便宜。
來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/shopping-offers
著作權(quán)歸領(lǐng)扣網(wǎng)絡(luò)所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系官方授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
2. 解題
2.1 狀態(tài)壓縮超時(shí)解
- 思路是,把int看做買東西的個(gè)數(shù)的狀態(tài),3個(gè)位最大是7,題目說不超過6,物品也不超過6,最多18位就可以了
- 一個(gè)int就可以存下買的物品的個(gè)數(shù)
- 最后一個(gè)例子超時(shí),可能這個(gè)最大的狀態(tài)數(shù)太大了
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維動(dòng)態(tài)規(guī)劃
- 把單個(gè)的也處理成大禮包,統(tǒng)一處理
- 不滿6個(gè)的都補(bǔ)滿,方便處理
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++
總結(jié)
以上是生活随笔為你收集整理的LeetCode 638. 大礼包(无限背包DP)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。