zoukankan      html  css  js  c++  java
  • Luogu T24242 购物券Ⅰ(数据已加强)

      这是一道比赛时的题目,但由于我没报名,所以浪费了一个大好的切水题的机会。

      是经典的meet in middle(折半搜索)的模板题,但是之前一直没找到这种题目,今天终于看到了。

      由于m的范围极大,因此一般的背包DP是行不通的。

      如果直接进行2^n的爆搜,也只有40分。

      所以这里我们观察数据n=40,发现如果是2^(n/2),就可以像前面一样跑过去。

      所以我们缩小范围,先在1到n/2的范围内找出所有m以内的价值的和,用hash来存(这里需要挂链);

      然后同样的在n/2+1到n的范围内找出所有m以内的价值的和,接着通过hash查询是否存在m-tot,如果有说明有解可以退出。

      这应该是meet in middle的最简单的合并两部分的方式了吧。

      需要注意的是hash的时候直接%一个数就可以了,不用乘来乘去浪费时间(我就是这样TLE了好几次),通过挂链来实现查询。

      具体实现看代码CODE

    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int N=45,mod=2333333;
    struct egde
    {
        int v,next;
    }link[(1<<20)+10];
    int head[mod],a[N],n,m,k;
    bool h[mod],flag;
    inline void read(int &x)
    {
        x=0; char ch=getchar();
        while (ch<'0'||ch>'9') ch=getchar();
        while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    }
    inline void add(int x,int y)
    {
        link[++k].v=y; link[k].next=head[x]; head[x]=k;
    }
    inline int hash(int k)
    {
        return k%mod;
    }
    inline void init(int k,int tot)
    {
        if (flag) return;
        if (tot==m) { flag=1; return; }
        if (k>n/2)
        {
            int t=hash(tot);
            h[t]=1; add(t,tot);
            return; 
        }
        if (tot+a[k]<=m) init(k+1,tot+a[k]);
        init(k+1,tot);
    }
    inline void DFS(int k,int tot)
    {
        if (flag) return;
        if (k>n)
        {
            int now=hash(m-tot);
            if (!h[now]) return;
            for (register int i=head[now];i!=-1;i=link[i].next)
            if (link[i].v==m-tot) { flag=1; break; }
            return;
        }
        if (tot+a[k]<=m) DFS(k+1,tot+a[k]);
        DFS(k+1,tot);
    }
    int main(void)
    {
        register int i;
        while (scanf("%d%d",&n,&m)!=EOF)
        {
            memset(h,0,sizeof(h));
            memset(link,-1,sizeof(link));
            memset(head,-1,sizeof(head));
            for (i=1;i<=n;++i)
            read(a[i]);
            k=flag=0;
            init(1,0);
            if (flag) { puts("YES"); continue; }
            DFS(n/2+1,0);
            puts(flag?"YES":"NO");
        }
        return 0;
    }
  • 相关阅读:
    JavaEE中Filter实现用户登录拦截
    【Tomcat】如何注册Tomcat到Window Service服务
    案例分析:项目组内踢皮球事件
    最大子序列求和问题
    《游戏脚本的设计与开发》-第一部分总结 文字脚本的功能扩展和一个游戏测试
    ajax异步请求实例
    创建用于编译和运行Java程序的批处理文件
    Codeforces Round #189 (Div. 2)
    新的研究方向
    怎样在android实现uc和墨迹天气那样的左右拖动效果
  • 原文地址:https://www.cnblogs.com/cjjsb/p/8644901.html
Copyright © 2011-2022 走看看