第九次总结 背包(二)

这周经过老师的讲解,发现上周的理解有一些错误。首先背包问题分为三种:
1.01背包
2.完全背包
3.多重背包
其中的题目、代码基本没问题。此外,补充一点,01背包在循环中是逆序的,顺序从N到1,而完全背包是正序的,顺序从1到N.。
再看多重背包,多重背包有了二进制的优化。
题目:

有k种石头,高为hi,在不超过ai的高度下,这种石头可以放置,有ci种这个石头,求这些石头所能放置的最高高度…
思路:以往的什么硬币种数,最大硬币数之类的,他们的硬币都已经是排好序了的,总是从小到大,但是这个题目不同,它有着最高高度的限制,那么在思考的时候,要得到最优的,那么首先就是要对ai排序…这是贪心,然后就是多重背包了

代码如下:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct node
{
    int h;
    int a;
    int c;
}s[500];
int dp[50000],num[41000];
int cmp(const node p,const node q)
{
    return p.a<q.a;
}
int main()
{
    int n;
    while(scanf("%d",&n)>0)
    {
        int maxx=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d %d %d",&s[i].h,&s[i].a,&s[i].c);
            if(maxx<s[i].a)
            maxx=s[i].a;
        }
        sort(s+1,s+1+n,cmp);
        memset(dp,0,sizeof(dp));
dp[0]=1;
        for(int i=1;i<=n;i++)
        {
            memset(num,0,sizeof(num));
            for(int j=s[i].h;j<=maxx;j++)
            if(dp[j-s[i].h]&&dp[j-s[i].h]+s[i].h>dp[j]&&dp[j-s[i].h]+s[i].h-1<=s[i].a&&num[j-s[i].h]<s[i].c)
            {
                dp[j]=dp[j-s[i].h]+s[i].h;
                num[j]=num[j-s[i].h]+1;
             }
        }
int maxn=0;
        for(int i=0;i<=maxx;i++)
        if(maxn<dp[i])
        maxn=dp[i];
        printf("%d\n",maxn-1);
    }
    return 0;
}


在自习中,看到后面还有分组的背包问题,一开始我以为是第四种,后来觉得应该是前面几种的集合或拓展。分组的背包问题中:
算法:
问题变成了每组物品有若干种策略:是选择本组的某一件,还是一件都不选。也就是说设f[k][v]表示前k组物品花费费用v能取得的最大权值
状态方程:
f[k][v]=max{f[k-1][v],f[k-1][v-c[i]]+w[i]|物品i属于组k}。
题目:

给定n门课,再用m天复习这n门课,然后给定一个n*m的矩阵A,A[i][j]表示用j天复习第i门课获得得收益。问用m天复习不同的课获得的最大收益。
将天数m作为背包的容量,科目数目作为背包的种类数目,天数j作为背包的重量,因为一个科目只能选一次(复习天数),对应于每组中的物品只能选一件,正好是分组背包问题。转移方程:dp[j]=max(dp[j-k]+a[i][k],dp[j])

#include<iostream>
#include<string.h>
int dp[105],a[105][105];
int max(int a,int b)
{
       if(a<b)
           return b;
       return a;
}
int main()
{
       int i,j,k,n,m;
       while(scanf("%d%d",&n,&m)!=EOF)
       {
              if(n==0&&m==0)
                  break;
              memset(dp,0,sizeof(dp));
              for(i=0;i<n;i++)
                for(j=1;j<=m;j++)
                  scanf("%d",&a[i][j]);
              for(i=0;i<n;i++)
                  for(j=m;j>=0;j--)
                     for(k=1;k<=j;k++)
                       dp[j]=max(dp[j],dp[j-k]+a[i][k]);
               printf("%d\n",dp[m]);
       }
       return 0;
}

那么,背包问题也到此结束了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值