当背包问题的w和v都巨大时,时间复杂度和空间复杂度都不能满足要求,只能利用双向搜索的方法来求解:
首先将数组分成量部分,对第一部分用位操作的方法来枚举所有的子集的w和v(和),然后排序,去重(去除那些明显不可能的解)
然后对第二部分进行同样的枚举操作,从而找到重量不超过的情况下,价值的最大值。
需要注意的是lower_bound函数的问题,在比较pair类型的元素时,first和second都会进行比较,导致会有一些小问题出现。
个人比较倾向于使用upper_bound(ps, ps+m make_pair(W-sw,INF))-1 的方式来实现。
//
// 162_large nk.cpp
// changlle
//
// Created by user on 1/10/16.
// Copyright (c) 2016 user. All rights reserved.
//
#include <iostream>
using namespace std;
typedef long long ll;
const ll INF=1000;
int n=4;
ll w[4]={2,1,3,2};
ll v[4]={3,2,4,2};
ll W=5;
pair<ll, ll> ps[1<<(20/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[j];
sv+=v[j];
}
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];// amazing!!!
for (int i=0;i<(1<<n2);i++) {
cout<<ps[i].first<<" "<<ps[i].second<<endl;
}
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=(upper_bound(ps,ps+m,make_pair(W-sw,INF))-1)->second;
//此处注意pair在lower_bound 和 upper_bound中的小问题~
res=max(res,sv+tv);
}
}
cout<<res<<endl;
}
int main() {
solve();
cout<<endl;
// pair<int,int> b[4]={ make_pair(1,1),make_pair(2,2),make_pair(3,3),make_pair(4,4)};
//
// cout<<(lower_bound(b,b+3,make_pair(5,5)))->second<<endl;//fuck~~keng
// return 0;
}