背包问题(北大图形实验室2008考研复试)

贪心算法解决背包问题有几种策略:

(i)一种贪婪准则为:从剩余的物品中,选出可以装入背包的价值最大的物品,利用这种规则,价值最大的物品首先被装入(假设有足够容量),然后是下一个价值最大的物品,如此继续下去。这种策略不能保证得到最优解。例如,考虑n=2,
w=[100,10,10], p =[20,15,15], c = 105。当利用价值贪婪准则时,获得的解为x= [ 1 , 0 , 0
],这种方案的总价值为2 0。而最优解为[ 0 , 1 , 1 ],其总价值为3 0。
(ii)另一种方案是重量贪婪准则是:从剩下的物品中选择可装入背包的重量最小的物品。虽然这种规则对于前面的例子能产生最优解,但在一般情况下则不一定能得到最优解。考虑n=
2 ,w=[10,20], p=[5,100], c= 2 5。当利用重量贪婪策略时,获得的解为x =[1,0], 比最优解[ 0 , 1
]要差。
(iii)还有一种贪婪准则,就是我们教材上提到的,认为,每一项计算yi=vi/si,即该项值和大小的比,再按比值的降序来排序,从第一项开始装背包,然后是第二项,依次类推,尽可能的多放,直到装满背包。
有的参考资料也称为价值密度pi/wi贪婪算法。这种策略也不能保证得到最优解。利用此策略试解n= 3 ,w=[20,15,15],
p=[40,25,25], c=30 时的最优解。虽然按pi /wi
非递(增)减的次序装入物品不能保证得到最优解,但它是一个直觉上近似的解。
而且这是解决普通背包问题的最优解,因为在选择物品i装入背包时,可以选择物品i的一部分,而不一定要全部装入背包,1≤i≤n。

即不论何种贪心算法,都不能保证得到最优解。

下面考虑使用动态规划的方法求解:

开始时考虑递归求解,但超时了,看来是递归的时间太长了。

#include<stdio.h>
#include<algorithm>
using namespace std;
struct thing
{
    int t;
    int value;
}ts[101];
int get_max(int i,int j)
{
    return i>j?i:j;
}
int get_result(int M,int T)
{
    if(T==0||M<=0)
        return 0;
    int result_tmp = get_max(get_result(M-1,T)+ts[M].value,get_result(M-1,T-ts[M].t));
    return result_tmp;
}
int main()
{
    int T,M;
    while(scanf("%d %d",&T,&M)!=EOF)
    {
        for(int i=0;i<M;i++)
        {
           scanf("%d %d",&ts[i].t,&ts[i].value);
        }
        int result = get_result(M,T);
        printf("%d\n",result);
    }
    return 0;
}

然后换成迭代,注意空间为负值时要将值设置为前一个物体未放入时的值:

#include<stdio.h>
#include<algorithm>
using namespace std;


struct thing
{
    int t;
    int value;
}ts[101];

int result[101][1001];

int get_max(int i,int j)
{
    return i>j?i:j;
}

int main()
{
    int T,M;
    while(scanf("%d %d",&T,&M)!=EOF)
    {
        for(int i=1;i<=M;i++)
        {
           scanf("%d %d",&ts[i].t,&ts[i].value);
        }


        for(int i=0;i<=1000;i++)
            result[0][i]=0;

        for(int i=1;i<=M;i++)
        {
           for(int j=1;j<=1000;j++)
           {
               if(j-ts[i].t>=0)
               {
                   result[i][j]=get_max(result[i-1][j-ts[i].t]+ts[i].value,result[i-1][j]);
               }
               else
                   result[i][j]=result[i-1][j];
           }
        }
        
       printf("%d\n",result[M][T]);
    }

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值