超大01揹包問題

2022-05-11 10:20:26 字數 1721 閱讀 8685

超大揹包問題:有n個重量和價值分別為w[i]和v[i]的物品,從這些物品中挑選總重量不超過w的物品,求所有挑選方案中價值總和的最大值。其中,1 ≤ n ≤ 40, 1 ≤ w[i], v[i] ≤ 10^15, 1 ≤ w ≤ 10^15.

這個問題給人的第一感覺就是普通的01揹包。不過,看完資料範圍會發現,這次價值和重量都可以是非常大的數值,相比之下n比較小。使用dp求解揹包為題的複雜度是o(nw),因此不能用來解決這個問題。此時我們應該利用n比較小的特點來尋找其他方法。

挑選物品的方案總共有2^n種,所以不能直接列舉,但是如果將物品分成兩半再列舉的話,由於每部分最多只有20個,這是可行的。我們把前半部分中的挑選方法對應的重量和價值總和記為w1、v1,這樣在後半部分尋找總重w2 ≤ w - w1時使v2最大的選取方法即可。

因此,我們要思考從列舉得到的(w2,v2)集合中高效尋找max的方法。首先,顯然我們可以排除所有價值小重量大的狀態;這一點可以按照w2、v2的字典序排序後做到。此後剩餘的元素都滿足w2[i] < w2[j] <=> v2[i] < v2[j],要計算max的話,只要尋找滿足w2[i] <= w'的最大的i就可以了。這可以用二分搜尋完成,剩餘的元素個數為m的話,一次搜尋需要o(logm)的時間。因為m≤2^(n/2),所以這個演算法總的時間複雜度是o(n * 2^(n/2)),可以在實現內解決問題。

#include#include

#include

#include

#include

#include

using

namespace

std;

#define n 4005

#define pi 4*atan(1.0)

#define mod 1000000007

#define met(a, b) memset(a, b, sizeof(a))typedef

long

long

ll;struct

node

}a[1

<<20

];ll w[n], v[n], w;

intn;

int find(int l, int

r, ll num)

else

r = mid-1

; }

return

ans;

}int

main()

}a[i].w =sw;

a[i].v =sv;

}sort(a, a+(1

<

int m = 1

;

for(int i=1; i

//去重; ll ans = 0

;

for(int i=0; i

<

}int index = find(0, m-1, w-sw);///

找到價值最大的容量不超過w-sw;

ans = max(ans, sv+a[index].v);

}printf(

"%i64d\n

", ans);

}return0;

}/*input:

51 3 2

2 4 2

output:

*/

view code

超大揹包問題(01揹包)

超大揹包問題 有n個重量和價值分別為w i 和v i 的物品,從這些物品中挑選總重量不超過w的物品,求所有挑選方案中價值總和的最大值。其中,1 n 40,1 w i v i 10 15,1 w 10 15.這個問題給人的第一感覺就是普通的01揹包。不過,看完資料範圍會發現,這次價值和重量都可以是非常...

超大揹包問題

運用二進位制,折半搜尋,其實我覺得本質就是狀壓思想,列舉前一半所有情況並儲存。然後排序保障總質量越大,價值越大。這裡相當於貪心。可以證明的,如果在一堆一一對應的數裡面,只取乙個,另外乙個數越大才越有可能是最優解。這個思想大概只能用在只取乙個上面。再列舉後半部分。算出每一種列舉方式的總質量,w wi就...

超大容量揹包問題

這個問題給人的第一感覺就是普通的01揹包。不過,看完資料範圍會發現,這次價值和重量都可以是非常大的數值,相比之下n比較小。使用dp求解揹包為題的複雜度是o nw 因此不能用來解決這個問題。此時我們應該利用n比較小的特點來尋找其他方法。挑選物品的方案總共有2 n種,所以不能直接列舉,但是如果將物品分成...