zoukankan      html  css  js  c++  java
  • [Usaco2005 Dec]Scales 天平

    题目描述

    约翰有一架用来称牛的体重的天平.与之配套的是N(1≤N≤1000)个已知质量的砝码(所有砝码质量的数值都在31位二进制内).每次称牛时,他都把某头奶牛安置在天平的某一边,然后往天平另一边加砝码,直到天平平衡,于是此时砝码的总质量就是牛的质量(约翰不能把砝码放到奶牛的那边,因为奶牛不喜欢称体重,每当约翰把砝码放到她的蹄子底下,她就会尝试把砝码踢到约翰脸上).天平能承受的物体的质量不是无限的,当天平某一边物体的质量大于C(1≤C<2^30)时,天平就会被损坏. 砝码按照它们质量的大小被排成一行.并且,这一行中从第3个砝码开始,每个砝码的质量至少等于前面两个砝码(也就是质量比它小的砝码中质量最大的两个)的质量的和. 约翰想知道,用他所拥有的这些砝码以及这架天平,能称出的质量最大是多少.由于天平的最大承重能力为C.他不能把所有砝码都放到天平上.

    现在约翰告诉你每个砝码的质量,以及天平能承受的最大质量.你的任务是选出一些砝码,使它们的质量和在不压坏天平的前提下是所有组合中最大的.

    输入格式

    第1行:两个用空格隔开的正整数N和C.

    第2到N+1行:每一行仅包含一个正整数,即某个砝码的质量.保证这些砝码的质量是一个不下降序列

    输出格式

    一个正整数,表示用所给的砝码能称出的不压坏天平的最大质量.


    第一眼想用背包来做这题,然而数据太大了......

    注意题中指明了砝码重量最慢的情况呈斐波那契式增长。通过输出斐波那契数列发现当n=45时Fib[n]就大于1e9了。所以这题的n实际上也就50的规模......

    既然动规的数组存不下,又没(lan)想(de)到(xiang)其它算法,先打个爆搜下去。火字旁细节了

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define maxn 1001
    using namespace std;
    
    int a[maxn];
    int m,n;
    long long ans,c[maxn];
    
    inline int read(){
    	register int x(0),f(1); register char c(getchar());
    	while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
    	while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x*f;
    }
    
    void dfs(int d,long long now){
    	if(d>n){ ans=max(ans,now); return; }
    	if(now+a[d]<=m) dfs(d+1,now+a[d]);//选
    	dfs(d+1,now);//不选
    }
    
    int main(){
    	n=read(),m=read();
    	for(register int i=1;i<=n;i++) a[i]=read();
    	for(register int i=1;i<=n;i++) c[i]=c[i-1]+a[i];
    	dfs(1,0);
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    然后考虑剪枝。首先我们可以倒着枚举砝码,这样产生的搜索树就会小很多;

    然后假设当前的答案为ans,最多的情况就是从当前位开始把后面的全部都选上。如果后面的砝码总重加上当前的重量都要小于等于ans的话那就没必要往下搜了。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #define maxn 1001
    using namespace std;
    
    int a[maxn];
    int m,n;
    long long ans,c[maxn];
    
    inline int read(){
    	register int x(0),f(1); register char c(getchar());
    	while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
    	while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x*f;
    }
    
    void dfs(int d,long long now){
    	if(d>n){ ans=max(ans,now); return; }
    	if(now+c[n]-c[d-1]<=ans) return;//最优性剪枝
    	if(now+a[d]<=m) dfs(d+1,now+a[d]);
    	dfs(d+1,now);
    }
    
    int main(){
    	n=read(),m=read();
    	for(register int i=n;i>=1;i--) a[i]=read();//倒着枚举
    	for(register int i=1;i<=n;i++) c[i]=c[i-1]+a[i];
    	dfs(1,0);
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    创建线程的多种方式
    第六届蓝桥杯大赛个人赛省赛(软件类)C语言B组--2015年
    第七届蓝桥杯大赛个人赛省赛(软件类)C语言B组--2016年
    postgressql安装
    freebsd上安装nginx+php记录
    ubuntu cpus 共享打印
    查找表_leetcode219
    查找表_leetcode217
    查找表_leetcode202
    查找表_leetcode205
  • 原文地址:https://www.cnblogs.com/akura/p/10902416.html
Copyright © 2011-2022 走看看