- #include <cstdio>
- #include <algorithm>
- #include <map>
- #include <vector>
- 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;
- pair<ll, ll> ps[1 << (maxn / 2)]; //(重量, 价值)
- void solve()
- {
- //枚举前半部分
- int n2 = n / 2;
- for (int i = 0; i < 1 << n2; i++){
- ll sw = 0, sv = 0;
- for (int j = 0; j < n2; j++){
- if (i >> j & 1){
- sw += w[i];
- sv += v[i];
- }
- }
- ps[i] = make_pair(sw, sv);
- }
- //去除多余的元素
- sort(ps, ps + (1 << n2));
- int m = 1;
- for (int i = 1; i < 1 << n2; i++){
- if (ps[m - 1].second < ps[i].second){
- ps[m++] = ps[i];
- }
- }
- //枚举后半部分并求解
- ll res = 0;
- for (int i = 0; i < 1 << (n - n2); i++){
- ll sw = 0, sv = 0;
- for (int j = 0; j < n - n2; j++){
- if (i >> j & 1){
- sw += w[n2 + j];
- sv += v[n2 + j];
- }
- }
- if (sw <= W){
- ll tv = (lower_bound(ps, ps + m, make_pair(W - sw, INF)) - 1) -> second;
- res = max(res, sv + tv);
- }
- }
- printf("%lld\n", res);
- }
超大背包问题 折半枚举法
最新推荐文章于 2023-08-11 04:20:33 发布