算法:背包问题+背包问题相似问题poj1017 xoj1062

本文深入探讨了信息技术领域的细分技术,包括前端开发、后端开发、移动开发等,提供了每个领域的核心技术和应用实例,帮助读者了解不同技术领域的特点和发展趋势。

---to be continued--

=========-2014-12-11=================================================

首先复习一下可分割背包

n种货物

w1,w2,w3,...,wn 【重】

v1,  v2,v3,..., vn   【价值】

背包容量C,要求尽可能装下更大价值的货物,其中每种货物都可以选择只装一部分(整数)或者不装。

贪心解法:根据n种货物的价值密度排序,从价值密度最大的开始,尽量装入更多的货物(贪心性质)。

可以证明,上面的贪心策略的局部最优解最后可以使全局解达到最优。

============================================================

现在看看xoj1062 题目描述就不重复了。题目描述:XOJ1062

由于要求获得尽可能少的纸币,从面值最大的开始,尽量拿更多的纸币去找钱。

一些算法细节,

1、5角、1角的面值将导致存在浮点数,原则上不喜欢用浮点,因此可以把所有面值乘以10。

2、找钱的模拟过程尽量简化。

由于每一种面值找钱的过程都类似:先看钱数*面值数有没有大于目前剩下要找的钱数,如果大于==>只取一部分来找钱,如果小于==>全部取了

可以用数组存每一个面值,只需要一次遍历数组就可以了。

【不要去一个一个判断,100块的写一段代码,50块的也写一段类似的代码==>效率极低,并且容易出错;

    后面有一题(类似的模拟过程尽可能最简最好)】

算法伪代码:

 i = 1..n //遍历一遍所有面值即可

 if v[i] * k[i] > C

     K+= (int)C/v[i] //找回去的纸币数目

     C = C - ( (int)C / v[i] )* v[i]

  else

     K+= k[i]

     C = C - k[i]* v[i]

完整的代码如下:(xoj1062,是不是特别简单?!)

#include <stdio.h>  
int v[6] = {500, 100, 50, 10, 5, 1};  
int k[6];  
int main()  
{  
    int N,C,K=0;  
    scanf("%d",&N);  
    for(int i = 0 ; i < 6; i++)  
        scanf("%d",&k[i]);  
    C=1000 - 25*N;  
    for(int i = 0 ; i < 6; i++)  
    {  
        if(v[i] * k[i] > C)  
        {  
            K+=C/v[i];  
            C-=( C/v[i] )* v[i];  
        }  
        else  
        {  
            K+=k[i];  
            C-=v[i] * k[i];  
        }  
    }  
    if(C == 0)  
        printf("%d",K);  
    else  
        printf("-1");  
    return 0;  
}  
现在来看一下poj1017 题目描述poj1017

这个问题解法是“模拟”,模拟一个装箱过程。

物品 -->(放入) 箱子【使箱子数尽量少】

要使总箱子数目最少-->令装箱后的空位置最小-->放入更大的物品为优先,然后统计其剩余空间,让小的物品填充进去-->最后再有剩下的小物品,就再开辟新的箱子来装。

(上面这段描述有些混乱,以后会更新)

因此,将物品按照大小分为2类,一类是直接装入箱子,一类是用来填充箱子的缝隙。

考虑箱子数目与各个种类物品的关系:

1*1,2*2,3*3,4*4,5*5,6*6大小的物品数目分别如下:

a    ,   b    ,   c    ,    d   ,   e    ,   f

设n为箱子的数目,那么:

首先,n += d+e+f, and 若干缝隙:5d个2*2大小缝隙+11e个1*1大小缝隙 

其次,查看c的数目是否为4的倍数。

if(c % 4)

     n+=c / 4 + 1;

     switch(c%4)

        case 1:   5个2*2大小缝隙+7个1*1大小缝隙

        case 2:   3个2*2大小缝隙+6个1*1大小缝隙

        case 3:   1个2*2大小缝隙+5个1*1大小缝隙

else

     n += c / 4

再次,就是将1*1和2*2的物品放入上面装箱的空隙中,假如还有剩下物品,再根据剩下的数目另外装箱。

现在发现,可以用两个变量(x和y分别记录)来记录刚刚在前2步中产生的1*1和2*2的空隙数,

x 1*1箱子空隙数

y 2*2箱子空隙数

先把2*2的物品放入空隙中,b - y

b - y > 0 说明2*2物品有剩:

                            b -= y;

                            n += b % 9 == 0 ?b / 9:(b / 9 +1,x += (9 - b % 9)*4);

                            y = 0;

b - y = 0 说明刚好

b - y < 0 说明物品填充不完这类空隙,那就需要1*1的物品来继续填充; x+=( 0 - (b-y) ) * 4

然后就是把1*1的物品放入缝隙了;

与上面的过程类似,这里就不在赘述了。代码如下:

#include<stdio.h>

intmain(){

    int a,b,c,d,e,f,x,y;//

    while(1){

       int n = 0;

       x = y = 0;

       scanf("%d%d%d%d%d%d",&a,&b,&c,&d,&e,&f);

       if(a==0&&b==0&&c==0&&d==0&&e==0&&f==0){

           break;

       }

       n += d + e + f;

       x += 11 * e;

       y += 5 * d;

       if(c % 4){

           n +=( c / 4 )+ 1;

           switch (c % 4)

           {

           case 1:

              x += 7;

              y += 5;

              break;

           case 2:

              x += 6;

              y += 3;

              break;

           case 3:

              x += 5;

              y += 1;

              break;

           }

       }

       else

           n += c / 4;

       a -= x,b -= y;

       x = y = 0;

       if(b > 0){

           if(b % 9){

              n += b/9 + 1;

              x += (9 - b % 9)*4;

           }

           else

              n += b / 9;

       }

       else if(b != 0){

           b = 0-b;     

           x += b*4;

       }

       a -= x;

       x = 0;

       if(a > 0){

           if(a % 36){

              n+=a/36 + 1;

              x+=(36 - a % 36);

           }

           else

              n+=a/36;

       }

       else if(a != 0){

           a = 0 - a;

           x += a;

       }

       printf("%d\n",n);

    }

    return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值