zoukankan      html  css  js  c++  java
  • ACdream1726-A Math game+(DFS+二分)+(DFS+前缀和)

    传送门

    官方题解:http://acdream.info/topic?tid=4246

    参考:https://www.cnblogs.com/nowandforever/p/4492428.html

    题意:在给定的n个数中,能否找到几个数使得这几个和等于H;

    思路:注意这道题的条件 0<n<=40, 0<=H<10^9, 0<=a[i]<10^9,其中 H 和 A [i] 给的比较大,dp的空间开不下,而n比较小,只有40,所以可以把所给的数分成20、20两部分,用dfs或者直接状态压缩从0至2^(n/2)循环来搞出每组所有可能的和(dfs+剪枝应该比循环快),然后再在第二部分找(H-第一部分的可能和)就可以了。卡了一下map和set。可以用hash或者二分来找

    ac代码(600+ms):

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    const int maxn = 1050000;        //比2的20次大一点
    
    int n,h,a[50],d[50],c[maxn],cnt,flag;
    
    int check(int s)
    {
        int le=1,ri=cnt;
        while(le<=ri)
        {
            int mid=(le+ri)>>1;
            if(c[mid]==s)return 1;
            if(c[mid]>s)
                ri = mid - 1;
            else le    = mid + 1; 
        }
        return 0;
    }
    
    void dfs(int sum,int cur,int nn,int on)//利用on使得两次dfs放在了一起
    {
        if(flag)return;
        if(cur==nn+1)
        {
            if(on)
                c[++cnt]=sum;
            else flag = check(h-sum);
            return;
        }
        for(int i=0;i<2;i++)
        {
            int t=sum+d[cur]*i;
            if(t > h)return;
            dfs(t,cur+1,nn,on);
        }
    }
    int main(){
        //freopen("in","r",stdin);
        while(~scanf("%d%d",&n,&h))
        {
            for(int i = 1; i <= n; i++)
            {
                scanf("%d",&a[i]);
            }
            cnt = flag = 0;
            int n1 = (n>>1), n2=n-n1;//(n>>1)没加括号WA了几次
            for(int i=1; i<=n1; i++)
            {
                d[i]=a[i];
            }
            dfs(0,1,n1,1);     //第一次先算出前一半的所有可能和;
            sort(c+1,c+cnt+1);
            for(int i=n1+1;i<=n;i++)
            {
                d[i-n1]=a[i];
            }
            dfs(0,1,n2,0);    //第二次求后一半的和 ,在用二分在前一半中找有没有对应的值
            if(flag)puts("Yes");
            else puts("No");
        }
    
        return 0;
    }
    View Code

    我一开始注意到n比较小,就直接dfs暴力,但是超时了;

    不过,我又看到有人没有用二分,只用了dfs+前缀和,0ms;

    自己写的(12+ms)

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn = 50;
    int h,a[maxn],sum[maxn],n,ans=0;
    void dfs(int cur,int s)
    {
        if(ans)return;
        if(s>sum[cur])return;
        if(sum[cur]==s||s==0){ans=1;return;}
       
       for(int i=n;i>=1;i--)
       {
            if(ans)return;
            if(a[i]<=s)
            {
                dfs(i-1,s-a[i]);
            }
       }
    }
    int main(){
       // freopen("in","r",stdin);
        while(~scanf("%d%d",&n,&h))
        {
            sum[0]=0;
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
            }
            sort(a+1,a+1+n);        //不sort一直超时
            for(int i=1;i<=n;i++)
            {
                sum[i]=sum[i-1]+a[i];
            }
            ans=0;
            dfs(n,h);
            if(ans)puts("Yes");
            else puts("No");
        }
     
        return 0;
    }
    View Code
  • 相关阅读:
    绝对定位和浮动的区别和运用
    xhtml css 漏 整理
    网站自适应设备屏幕
    CSS 媒体查询 响应式
    js/jquery判断浏览器 & 停止加载
    回调函数之同步调用、回调、异步调用
    Flash生成HTML5动画方法
    在html页面中使用js变量
    BZOJ 4417 Luogu P3990 [SHOI2013]超级跳马 (DP、矩阵乘法)
    NOI2019游记
  • 原文地址:https://www.cnblogs.com/ckxkexing/p/8562433.html
Copyright © 2011-2022 走看看