• 【t038】&&【u214】金字塔


    Time Limit: 1 second
    Memory Limit: 128 MB

    【问题描述】

    小X来到一个雄奇的金字塔挖宝,但是这是一座被诅咒的金字塔,小X必须马上逃离这里,否则小X就会被埋在金字塔里,但他不希望此行落空。 
    现在小X面前有N+1种财宝,每种财宝都有一个价值。第一种财宝重量为0,第二种财宝重量为1,总之第I种财宝重量为I-1。现在小X希望
    拿走N+M个物品,但是这M+N个物品总重量不能超过N。小X希望能获得最大的价值。你能帮帮他吗?
    由于金字塔跟小X一样牛,所以每种财宝无限个。


    【输入格式】

    第一行两个正整数N,M 第二行N+1个整数,第I个整数代表了第I种财宝的价值

    【输出格式】

    一个数,表示最大利润。

    【数据规模】

    10%满足N,M<=10 40%满足N,M<=100 100%满足 N,M<=3000 abs(财宝价值)<=1000

    Sample Input1

    5 3
    4 7 2 5 -3 6
    
    
    
    
    

    Sample Output1

    47

    【题解】

    这题有两个很烦人的地方,一个是m+n个物品的限制。一个是重量为0的物品。

    我们要怎么去除掉这个问题呢。

    首先考虑一下最后我们选取的物品。

    因为规定了要选m+n个物品。如果不选重量为0的物品可能会出现选不够的问题。

    因此必然是掺杂着重量为0和重量不为0的物品。设为x,y.

    设重量为0的物品下标为0,重量不为0的物品下标为1..n;

    c是物品价值数组,w是物品的重量数组。

    最后的答案 == x*c[0] + y*c[0] +∑(c[i]) - y*c[0]  (其中的求和为所选出的最优的y个有重量的物品的价值的和);

    但是先别急着划掉两个y*c[0];

    我们合并一下。ans == (x+y)*c[0] + ∑(c[i]) - y*c[0];

    其中x+y==n+m;

    ans == (n+m)*c[0] + ∑(c[i]) - y*c[0];

    其中左边绿色部分为常量,右边为需要求的量。

    因为∑(c[i])一共求和了y(未知)个c[i],则可以再化一下。

    ans == 常量 + ∑(c[i]-c[0]) i∈【1,n】

    这下问题就变成求物品重量为w[i],价值为c[i]-c[0]的完全背包问题了。

    右边最大则ans最大。

    还有一个优化的方法。即如果c[i]-c[0]是小于0的,那么这个物品就不要了。

    因为如果c[i]比c[0]还小,那么拿不用重量的物品来替代i物品肯定最优。(c[0]不用消耗重量!)

    【代码】

    #include <cstdio>
    
    int n,m,temp,num = 0,f[3011],w[3011],c[3011];
    
    void input_data()
    {
    	scanf("%d%d",&n,&m);
    	scanf("%d",&temp); //读入c[0] 
    	for (int i = 1;i <= n;i++)
    		{
    			int x;
    			scanf("%d",&x); 
    			x -= temp; //输入第i个物品的价值,先减去c[0] 
    			if (x > 0) //如果减去后还大于0则这个物品是可能在y个物品中的。 
    				{
    					num++;
    					w[num] = i;
    					c[num] = x;
    				}
    		}
    }
    
    void get_ans()
    {
    	for (int i = 1;i <= num;i++) //对c[i]-c[0] (i∈[1..n]) 进行完全背包的过程 
    		for (int j = w[i];j <= n;j++)
    			if (f[j] < f[j-w[i]] + c[i])
    				f[j] = f[j-w[i]] + c[i];
    }
    
    void output_ans()
    {
    	printf("%d",f[n] + (n+m)*temp);	//最后输出f[n]的时候还要加上被减去的y个c[0]。以及x个c[0]; 
    }
    
    int main()
    {
    	//freopen("F:\rush.txt","r",stdin);
    	input_data();
    	get_ans();
    	output_ans();
    	return 0;	
    }



  • 相关阅读:
    Atitit 图像金字塔原理与概率 attilax的理解总结qb23
    Atiti  attilax主要成果与解决方案与案例rsm版 v4
    Atitit 常用比较复杂的图像滤镜 attilax大总结
    Atitit. Api 设计 原则 ---归一化
    Atitit 面向对象弊端与问题 坏处 缺点
    Atitit  记录方法调用参数上下文arguments
    Atitit 作用域的理解attilax总结
    Atitit usrQBM1603短信验证码规范
    atitit 短信验证码的源码实现  .docx
    Atitit 图片 验证码生成attilax总结
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632373.html
Copyright © 2020-2023  润新知