一道折半枚举
n<=45
分成两半 一半23一半22
再枚举枚举每一半的东西选或者是不选(复杂度O2^(n/2))
然而有几个优化是需要的
首先要通过dfs查找需要什么,因为很多的状态是多余的
接着找出后要进行排序(两边都需要)
再用一个id表明当前的位置
就可以做到O(n)的查找了
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
inline unsigned max(unsigned x,unsigned y)
{
if(x<y)
{
return y;
}
return x;
}
inline unsigned read()
{
register unsigned x=0,f=1,ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-'){f=-1;}ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0',ch=getchar();}
return x*f;
}
unsigned w,n,cost[50],q1[(1<<23|1)],tail1,n1,n2,x,ans,t,q2[(1<<23|1)],tail2;
inline void dfs(unsigned id,unsigned data)
{
if(data>w)
{
return ;
}
if(id>n1)
{
tail1++;
q1[tail1]=data;
return ;
}
dfs(id+1,data+cost[id]);
dfs(id+1,data);
}
inline void bfs(unsigned id,unsigned data)
{
if(data>w)
{
return ;
}
if(id>n2)
{
tail2++;
q2[tail2]=data;
return ;
}
bfs(id+1,data+cost[id+n1]);
bfs(id+1,data);
}
inline int cmp(int a,int b)
{
return a>b;
}
int main()
{
w=read(),n=read();
n1=n/2+1;
n2=n-n1;
register unsigned i,id=0;
for(i=1;i<=n;i++)
{
cost[i]=read();
}
dfs(1,0),
sort(q1+1,q1+1+tail1),
bfs(1,0),
sort(q2+1,q2+1+tail2);
id=tail1;
for(i=1;i<=tail2;i++)
{
while(id>1&&(long long)q1[id]+q2[i]>w)
{
id--;
}
ans=max(ans,q1[id]+q2[i]);
}
printf("%u",ans);
return 0;
}