zoukankan      html  css  js  c++  java
  • 【9918】逃亡的准备

    Time Limit: 1 second
    Memory Limit: 128 MB

    【问题描述】

    在《Harry Potter and the Deathly Hallows》中,Harry Potter 他们一起逃亡,现在有许多的东西要放到赫敏的包里面,但是包的大小优先,所以我们只能够在里面放入非常重要的物品,现在给出该种物品的数量、体积、价值和数值,希望你能够算出怎样能使背包的价值最大的组合方式,并且输出这个数值,赫敏会非常地感谢你

    【输入格式】

    第一行有2个整数,物品种数n和背包装载体积v。 2行到i+1行每行3个整数,为第i种物品的数量m,体积w、价值s。对于100%的数据1≤v≤500,1≤n≤2000,1≤m≤5000,1≤w≤20,1≤s≤100

    【输出格式】

    输出文件为一个整数,即为能拿到的最大的物品价值总和。

    Sample Input

    2 10
    3 4 3
    2 2 5
    

    Sample Output

    13
    

    【题解】

    这题平台上的实际时限是5s。如果是5s只要用普通的多重背包算法即可通过。

    但如果要在1s内通过。则需要用到二进制分解背包。

    比如有一个类型的物品,有50个

    31 的二进制是11111

    而111111 == 63 > 50

    所以我们先获得2^0 2^1 2^2 2^3 2^4.

    然后用50-31;

    得19;

    然后我们再获得19;

    总共我们获得了 1 2 4 8 16 19 这几个数字;

    然后 我们就可以用这几个数字组合成1-50中任意的数字了。

    于是我们生成若干个物品,他们的价值分别是1*c[i],2*c[i],4*c[i].....19*c[i],重量也同样扩大,即1*w[i],2*w[i],4*w[i]...19*w[i];

    接下来解释重点。

    为什么用这几个数字就能组合成1-50中的任意数字?

    首先 1-31这些数字是肯定可以的了。

    因为1-31就是xxxxx(5个数字)这样的情况。x可能等于1或0.这是其二进制形式。如果某个x等于1就相应的加上2^d就可以啦。

    然后就是32-50

    比如40

    这些数字全部加起来等于50;

    那么也就是说我们要除去一系列的数,且这些数的和等于10;

    而1-31这些数字都能由1 2 4 8 16得来。所以 10也就没问题了。用这些数字中的一些数字组合成10,然后去掉就可以了。

    综上 1 2 4 8 16 19这些数字可以组合成1-50中的任意一个数字。

    生成那些物品后,就可以当做0/1背包问题来解决了

    【题解】

    #include <cstdio>
    #include <cstring>
    
    int n,m,w[90000],c[90000],f[600],nn = 0,temp[20]; //因为用了二进制分解,所以物品的数量会增加 
    
    void init()
    {
    	temp[0] = 1;
    	for (int i = 1;i <= 16;i++) //先获取2^i的值 预处理可以省去很多时间 
    		temp[i] = temp[i-1]*2;
    }
    
    void input_data()
    {
    	scanf("%d%d",&n,&m);
    	for (int i = 1;i <= n;i++)
    		{
    			int num,ww,cc;				
    			scanf("%d%d%d",&num,&ww,&cc);
    			int now = 0;
    			while (num >= temp[now]) //如果还能分则减 
    				{
    					nn++;
    					w[nn] = ww*temp[now]; //生成一个扩大temp[now]倍的物品 
    					c[nn] = cc*temp[now];
    					num-=temp[now]; //减掉 
    					now++;
    				}
    			if (num >0) //如果还有剩余的。就用剩下的数字生成一个扩大相应倍数的物品 
    				{
    					nn++;
    					w[nn] = num*ww;
    					c[nn] = num*cc;	
    				}
    		}
    }
    
    void get_ans()
    {
    	memset(f,0,sizeof(f));
    	for (int i = 1;i <= nn;i++)
    		for (int j = m;j >= w[i];j--) //逆序更新,这是0/1背包的做法。 
    			if (f[j] < f[j-w[i]] + c[i])
    				f[j] = f[j-w[i]] + c[i];
    			
    }
    
    void output_ans()
    {
    	printf("%d",f[m]);
    }
    
    int main()
    {	
    	//freopen("F:\rush.txt","r",stdin);
    	init();
    	input_data();
    	get_ans();
    	output_ans();
    	return 0;
    }



  • 相关阅读:
    linux相关的常用站点
    基于命令行的网络调试和测试工具
    清除DNS缓存
    数组映射
    react-native 自定义多选
    weex 长按图片保存
    MySql常用总结
    git常用命令
    react-native 自制多选功能
    react-native setState无法保持更新
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632382.html
Copyright © 2011-2022 走看看