162_超大背包问题 (双向搜索)

  当背包问题的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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值