HDU2191悼念512汶川大地震遇难同胞——珍惜现在,感恩生活

急!灾区的食物依然短缺!
为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种大米,每种大米都是袋装产品,其价格不等,并且只能整袋购买。
请问:你用有限的资金最多能采购多少公斤粮食呢?

后记:
人生是一个充满了变数的生命过程,天灾、人祸、病痛是我们生命历程中不可预知的威胁。
月有阴晴圆缺,人有旦夕祸福,未来对于我们而言是一个未知数。那么,我们要做的就应该是珍惜现在,感恩生活——
感谢父母,他们给予我们生命,抚养我们成人;
感谢老师,他们授给我们知识,教我们做人
感谢朋友,他们让我们感受到世界的温暖;
感谢对手,他们令我们不断进取、努力。
同样,我们也要感谢痛苦与艰辛带给我们的财富~


 

Input
输入数据首先包含一个正整数C,表示有C组测试用例,每组测试用例的第一行是两个整数n和m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。
 

Output
对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占一行。
 

Sample Input
  
  
1 8 2 2 100 4 4 100 2
 

Sample Output

400

方法一:循环输入并判断n个物品,最外圈循环该物品的数量,然后判断是加入该物品还是不加入更合理,如果判断的所有价格中都是不选更合理,就不用再循环物品的下一个数目,直接数目循环,然后开始第二个物品的数目循环

代码如下

#include 
     
     
      
      
#include 
      
      
       
       
#include 
       
       
        
        
#define maxn 110
int pay,n;
int dp[maxn];
using namespace std;
int main()
{
    int c;
    while(~scanf("%d", &c))
    {
        while(c--)
        {
            memset(dp, 0, sizeof(dp));
            scanf("%d%d", &pay, &n);
            //种类
            for(int i = 0; i < n; i++)
            {
                int p, w, m;
                scanf("%d%d%d", &p, &w, &m);
                //数目
                for(int j = 0; j < m; j++)
                {
                    int bk = 1;
                    //金额
                    for(int k = pay; k >= p; k--)
                    {
                        if(dp[k] < dp[k - p] + w)
                        {
                            dp[k]= dp[k - p] + w;
                            bk = 0;
                        }
                    }
                    if(bk)
                        break;
                }

            }
            printf("%d\n",dp[pay]);
        }
    }
    return 0;
}

       
       
      
      
     
     
方法二=.=:大神总是厉害的,利用二进制来简便算法!!!同样是循环数目,数目增加按照2的n次方进行增加,如果2的零次方和一次方都选了就是3=.=,详细看代码
#include 
      
      
       
       
#include 
       
       
        
        
#define maxn 110

int n, pay, f[maxn];

using namespace std;


bool make(int pi,int wi){
    bool bk = 1;
    //=.=第一次金额由pay循环到p * 1,重量为w * 1
    //第二次金额由pay循环到p * 2,重量为w * 2
    //啊啊啊!!是不是循环第一次选择了循环第二次也选择了
    //额,就变成了选择了三个(┬_┬)
    //第三次金额由pay循环到p * 4,重量为w * 4
    for(int j = pay; j >= pi; --j)
    {
        if(f[j] < f[j - pi] + wi)
        {
            f[j] = f[j - pi] + wi;
            bk = 0;
        }
    }
    return bk;
}
int main()
{
    int c;
    while(~scanf("%d", &c))
    {
        while(c--)
        {
            scanf("%d%d", &pay, &n);
            for(int i = 0; i <= pay; ++i)
                f[i] = 0;
            for(int i = 1; i <= n; ++i)
            {
                int p, w , m;
                scanf("%d%d%d", &p, &w, &m);
                int t = 1;
                bool bo = 0;
                while(t <= m)
                {
                    //如果当前加入的个数在所有金额循环中都是不取更高
                    //那么就不必再循环加入更多的此物品
                     bo = make(t * p, t * w);
                     if(bo) break;
                     m -= t;//第一次循环:m - 1
                     //第二次过来,m - 1 - 2
                     //第三次过来m - 1 - 2 - 4
                     //为啥m也减呢???
                     //m 所减的总数是当前次t的值
                     //即执行完下一步以后的t值
                     //那个while条件就是当循环一半m数目的时候
                     //然后最后一次执行以后所有的次数执行为m或者m - 1;
                     t *= 2;//咩咩咩??
                     //第一次循环:t = 2
                     //第二次:t = 4;
                     //利用二进制!!!
                }
                //最后的bo都是不插入当前元素所得重量更大,就没必要再循环下面插入m的操作
                if(bo) continue;
                if(m) make(m * p, m * w);
            }
            printf("%d\n", f[pay]);
        }
    }
    return 0;
}

       
       
      
      

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值