zoukankan      html  css  js  c++  java
  • 【t077】宝物筛选

    Time Limit: 1 second
    Memory Limit: 128 MB

    【问题描述】

    小FF找到了王室的宝物室,里面堆满了无数价值连城的宝物……这下小FF可发财了。但是这里的宝物实在是太多了,小FF的采集车
    似乎装不下那么多宝物。看来小FF只能含泪舍弃其中的一部分宝物了……小FF对洞穴里的宝物进行了整理,他发现每样宝物都
    有一件或者多件,他粗略的估算了下每样宝物的价值,之后开始了宝物筛选工作:小FF有一个最大载重为W的采集车,洞穴里总
    共有n种宝物,每种宝物的价值为v[i],重量为w[i],每种宝物有m[i]件。小FF希望在采集车不超载的前提下,选择一些宝物装
    进采集车,使得它们的价值和最大。 【数据范围】
    对于30%的数据:n≤∑m[i]≤10^4; 0≤W≤10^3
    对于100%的数据:n≤∑m[i]≤10^5;0≤W≤4*10^4; 1≤n≤100. 

    【输入格式】

    第一行为一个整数N和W,分别表示宝物种数和采集车的最大载重。
    接下来n行每行三个整数,其中第i行第一个数表示第i类品价值,第二个整数表示一件该类物品的重量,第三个整数为该类物品数量。 

    【输出格式】

    输出仅一个整数ans,表示在采集车不超载的情况下收集的宝物的最大价值。

    Sample Input

     4  20
        3  9  3
        5  9  1
        9  4  2
        8  1  3
    
    
    
    
    

    Sample Output

     47

    【题解】

    这题的同种物品数量很多。很多嘛。肯定就要用特殊的办法。那就是,那就是,那就是二进制优化。

    比如有一个类型的物品,有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,temp[30],w[2000],c[2000],nn = 0,f[50000];
    
    void init()
    {
    	temp[0] = 1;//2^0 == 1 
    	for (int i = 1;i <= 20;i++) //获取2^i 存入temp[i]中 
    		temp[i] = temp[i-1] * 2;
    }
    
    void input_data()
    {
    	scanf("%d%d",&n,&m);
    	for (int i = 1;i <= n;i++) //输入n个物品的信息 
    		{
    			int cc,ww,num;
    			scanf("%d%d%d",&cc,&ww,&num);	
    			int now =0;
    			while (num >= temp[now]) //temp[i]表示2^i now一开始等于0 
    				{
    					nn++;
    					w[nn] = temp[now]*ww; //扩大成一个新的物品。 
    					c[nn] = temp[now]*cc;
    					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);
    	//freopen("F:\rush_out.txt","w",stdout);
    	init();
    	input_data();
    	get_ans();
    	output_ans();
    	return 0;
    }



  • 相关阅读:
    WPF DelegateCommand 出现Specified cast is not valid
    WPF DelegateCommand 出现Specified cast is not valid
    WPF DelegateCommand 出现Specified cast is not valid
    win10 sdk 是否向下兼容
    win10 sdk 是否向下兼容
    win10 sdk 是否向下兼容
    PHP extract() 函数
    PHP end() 函数
    PHP each() 函数
    PHP current() 函数
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632393.html
Copyright © 2011-2022 走看看