版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/89422276
题目:CH2401.
题目大意:给定
个物品的重量
以及一个上限
,要求挑选一些物品使得
之和小于等于
且最接近
.
.
看起来是道背包模板题,但是由于 太大只能考虑搜索了.
很容易发现搜索是 的,复杂度太高,但是可以发现 级别的算法是可以通过这道题的,所以考虑双向搜索.
考虑把礼物分成两部分,第一部分把所有可能得到的 和放入一个数组中排序,第二部分直接大力搜索,每次凑出一种情况,就把当前的 和与第一部分中的一个组合,可以通过二分实现.
时间复杂度 .
在具体实现的过程中,可以把 从大到小排序,并且由于第二部分的复杂度多了 ,所以可以给第一部分多分配一点来到达优化的效果.
还有一点要注意,这道题两个int相加会爆int…
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
typedef unsigned int UI;
const int N=45;
int tx,n;
UI w,x[1<<N/2+3],a[N+9],mx;
bool cmp(const UI &a,const UI &b){return a>b;}
void dfs1(int k,UI s){
if (s>w) return;
if (k>n/2+2) {x[++tx]=s;return;} //由于第二个搜索复杂度多个O(n),所以前面搜多一点会更快
dfs1(k+1,s);
dfs1(k+1,s+a[k]);
}
UI Upper(int k){
int l=0,r=tx,mid=l+r+1>>1;
for (;l<r;mid=l+r+1>>1)
k<x[mid]?r=mid-1:l=mid;
return x[l];
}
void dfs2(int k,UI s){
if (s>w) return;
if (k>n) {mx=max(mx,s+Upper(w-s));return;}
dfs2(k+1,s);
dfs2(k+1,s+a[k]);
}
Abigail into(){
scanf("%u%d",&w,&n);
for (int i=1;i<=n;++i)
scanf("%u",&a[i]);
}
Abigail work(){
sort(a+1,a+1+n,cmp); //貌似从大到小排序会快一点
dfs1(1,0);
sort(x+1,x+1+tx);
mx=x[tx];
dfs2(n/2+3,0);
}
Abigail outo(){
printf("%u\n",mx);
}
int main(){
into();
work();
outo();
return 0;
}