**:
題意:有重量和價值分別為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 思路顯然是無法求解的,揹包的體積太大了,那麼就要換種思考的方向,觀察物品的數量...