超大揹包問題 (折半列舉)

2021-08-11 07:45:49 字數 1314 閱讀 3944

**:

題意:有重量和價值分別為wi,vi的n個物品。從這些物品中挑選總重量不超過w的物品,求所有挑選方案中價值總和的最大值。

限制條件:

1 <= n <= 40

1 <= wi, vi <= 10 的15次冪

1 <= w <= 10的15次冪

輸入:n = 4

w =

v =

w = 5

輸出:7(挑選0、1、3號物品)

分析:

這個問題是前面介紹過的揹包問題,不過這次價值和重量都可以是非常大的數值,相比之下n比較小。使用dp求解揹包問題的複雜度是o(nw),因此不能用來解決這裡的問題。

我們可以向之前的題一樣拆成兩半之後再列舉,因為每部分只有20個,所以是可行的。利用拆成兩半後的兩部分的價值和重量,我們能求出原先的問題。

我們把前半部分中的選取方法對應的重量和價值總和記為w1, v1。這樣在後半部分尋找總重w2 <= w - w1時使v2最大的選取方法就好了。

因此,我們要思考從列舉得到的(w2, v2)的集合中高效尋找max的方法。首先,顯然我們可以排除所有w2[i] <= w2[j]並且v2[i] >= v2[j]的j。這一點可以按照w2, v2的字典序排序後簡單做到。此後剩餘的元素都滿足w2[i] < w2[j]===v2[i] < v2[j],要計算max的話,只要尋找滿足w2[i] <= w'的最大的i就可以了。這可以用二分搜尋完成。

#include #include #include #include using namespace std;

typedef long long ll;

const int maxn = 40 + 5;

const int inf = 10000000;

int n;

ll w[maxn], v[maxn];

ll w;

pairps[1 << (maxn / 2)]; //(重量, 價值)

void solve()

}ps[i] = make_pair(sw, sv);

}//去除多餘的元素

sort(ps, ps + (1 << n2));

int m = 1;

for (int i = 1; i < 1 << n2; i++)

}//列舉後半部分並求解

ll res = 0;

for (int i = 0; i < 1 << (n - n2); i++)

}if (sw <= w)

}printf("%lld\n", res);

}

超大揹包問題 折半列舉

超大揹包問題 有重量和價值分別為wi,vi的n個物品,從這些物品中挑選總重量不超過w的物品,求所有挑選方案中價值總和的最大值。1 1 1因為wi,太大,陣列開不了,而我們發現n的數量較少,可以使用折半列舉。首先列舉前n 2個揹包的所有可能結果,儲存在結構體ps n sv ps n sw中,然後按sw...

超大揹包問題(折半列舉)

超大揹包問題 有重量和價值分別為w i v i 的n個物品,從這些物品中選出總重不超過w的物品,求所有挑選方案中價值總和的最大值 1 n 40 1 w i v i 1e15 1 w 1e15 輸入第一行為n,接著輸入一行w i 和一行v i 最後輸入w佔單獨一行 輸出單獨一行即所有挑選方案中價值總和...

超大揹包問題 折半搜尋

超大揹包問題 有n個重量和價值分別為w i 和v i 的物品,從這些物品中挑選總重量不超過w的物品,求所有挑選方案中價值總和的最大值。其中,1 n 40,1 w i v i 10 15,1 w 10 15.按照普通的dp 思路顯然是無法求解的,揹包的體積太大了,那麼就要換種思考的方向,觀察物品的數量...