zoukankan      html  css  js  c++  java
  • wikioi 2144 分步二进制枚举+map记录

    有n个砝码,如今要称一个质量为m的物体,请问最少须要挑出几个砝码来称?

    注意一个砝码最多仅仅能挑一次

    第一行两个整数n和m。接下来n行每行一个整数表示每一个砝码的重量。

    输出选择的砝码的总数k,你的程序必须使得k尽量的小。

    3 10
    5
    9
    1

    2

    1<=n<=30。1<=m<=2^31,1<=每一个砝码的质量<=2^30


    思路:这题刚開始用了搜索。不机智T了又WA了。然后又一次回到二进制枚举上来吧。

    刚開始读题的时候想用二进制枚举了,可是无奈n<=30。2^30早就T了,所以用不了二进制枚举。

    搜索又T又WA的,然后仅仅好看了一下解题报告。里面说了用二进制枚举,可是分块来枚举就不会T了。呀!真是太机智了大神们!!

    由于最多有30个数。而他们的组合都会非常大的,可是假设我们先搞先n/2个数的组合,然后再搞后(n+1)/2个数的组合的话。然后再把前后合成,就不会T了,并且也能够保证前后组合后与标准的组合是一样的。分治的思想。

    二进制又进步了非常多,曾经是20下面的才敢二进制枚举。如今20以上的用了分治思想后也能够用二进制枚举了。历害。。!

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<map>
    using namespace std;
    int main()
    {
        int n,m,a[33],i,j,ans=1000000007;
        map<int,int>mm;
        cin>>n>>m;
        for(i=0;i<n;i++)
            cin>>a[i];
        for(i=1;i<(1<<(int)(n/2+1));i++)
        {
            int sum=0,cnt=0;
            for(j=0;j<n/2;j++)
                if(i&(1<<j)) sum+=a[j],cnt++;
            if(!mm[sum]||cnt<mm[sum]) mm[sum]=cnt;
        }
        if(mm[m]) ans=mm[m];
        for(i=1;i<(1<<(int)((n+1)/2+1));i++)
        {
            int sum=0,cnt=0;
            for(j=0;j<(n+1)/2;j++)
                if(i&(1<<j)) sum+=a[j+n/2],cnt++;
            if(sum==m) ans=min(ans,cnt);
            if(mm[m-sum]) ans=min(ans,mm[m-sum]+cnt);
        }
        cout<<ans<<endl;
        return 0;
    }
    


查看全文
  • 相关阅读:
    【转载】Linux下各文件夹的含义和用途
    【转载】Linux 通过mount -o loop 配置本地.iso镜像为yum源(yum仓库)
    Fedora 和 RedHat 以及 SUSE 中 YUM 工具的使用
    【转】下载对应内核版本的asmlib
    【转】VMWare vCenter 6.0安装配置
    【转】在VMware中为Linux系统安装VM-Tools的详解教程
    【转】虚拟化(五):vsphere高可用群集与容错
    html拼接时onclick事件传递json对象
    bootstrap table 解析写死的json.并且把进度条放进列中。
    开发规范实体和值对象
  • 原文地址:https://www.cnblogs.com/ldxsuanfa/p/10926531.html
  • Copyright © 2011-2022 走看看