《算法竞赛进阶指南》0x24迭代加深 子集和问题

题目链接:https://www.acwing.com/problem/content/173/

要求从n件物品中选出若干件,重量之和不超过w并且最接近w,由于有45件最多,所以O(2^n)时间复杂度过高,可以考虑减半先搜索出结果,用另一半在前一半中二分寻找,

最终拼成结果,时间复杂度约为O(2^n/2*n)

代码:

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
#define maxn 100
typedef long long ll;
unsigned int  n,w,g[maxn];
vector<unsigned int > v; 
unsigned int ans;
int m ;
void dfs1(int now,unsigned int tot){//搜索前一半 
    if(!now){
        v.push_back(tot);
        return ;
    }
    dfs1(now-1,tot);//不选第i件,
    if(g[now]+tot <= w)dfs1(now-1,g[now]+tot); 
}
void dfs2(int now,unsigned int  tot){
    if(now==n+1){
        unsigned int y=*--upper_bound(v.begin(),v.begin()+m,w-tot);//查找最后一个小于等于w-tot的值 
        ans=max(ans,tot+y);
        return; 
    }
    dfs2(now+1,tot);
    if(g[now]+tot <= w)dfs2(now+1,g[now]+tot);
}
bool cmp(unsigned int &a,unsigned int &b){return a>b;}
int main(){
    cin>>w>>n;
    for(int i=1;i<=n;i++)cin>>g[i];
    sort(g+1,g+n+1,cmp);//优化搜索顺序 
    int k=n/2+2;
    dfs1(k,0);//先处理出前一半 
    sort(v.begin(),v.end());
    m=unique(v.begin(),v.end())-v.begin();
    dfs2(k+1,0);
    cout<<ans<<endl;
}

猜你喜欢

转载自www.cnblogs.com/randy-lo/p/13164627.html