tyvj1340送礼物 折半枚举

来源:互联网 发布:流星网络电视 2.88 编辑:程序博客网 时间:2024/04/30 09:31

一道折半枚举
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;}
1 0
原创粉丝点击