寒假1.20日所学--动态规划背包问题

1 背包问题 (二维暴力做法)

实质 递归问题:

思想:

f[i][j]表示只看前i个物品,总体积为j的情况下,总价值最大为多少

result:max{f[n][0~V]}

递归链条:

f[i][j]的求法:

( 假设已经把i-1个物品的状态已经计算完 现求的 i 个的状态 )

1. 不选第 i 个物品:f [ i ][ j ]=f [ i-1][ j ];  //只看前i-1个物品 体积为 j 时的最大价值

2. 选第 i 个物品:f [ i ][ j ]=f [ i-1 ][ j-v[i] ]+w[ i ]; //若选了i,则前i-1个物品所能用的体积为j-v[i];

则最终结果为f[i][j]=max[1.,2.];

递归初始化:

f[0][0]=0;  --在任何物品都未选时,体积为0 最大价值为0;

代码实现:

#include<bits/stdc++.h>
using namespace std;

int m,n,i,j;
int f[1010][1010];
int v[1010],w[1010];

int main()
{
    
    cin>>n>>m;
    
    for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
    
    for(int i=1;i<=n;i++)
    {
        
        for(int j=0;j<=m;j++)
        {
            
            f[i][j]=f[i-1][j];
            
            if(j>=v[i])
            {
                
                f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
                
            }
            
        }
        
    }
    
    int ans=0;
     
    for(int i=0;i<=m;i++)ans=max(ans,f[n][i]);

 //前n个物品 即所有物品 体积为 i 时可达的最大价值
    
    printf("%d",ans);    
    return 0;
}

2 背包问题 一维数组简化:

优化后程序占用空间减少:

代码实现:

#include<bits/stdc++.h>
using namespace std;

int m,n,i,j;
int f[1010];
int v[1010],w[1010];

int main()
{
    
    cin>>n>>m;
    
    for(int i=1;i<=n;i++)cin>>v[i]>>w[i];
    
    for(int i=1;i<=n;i++)
    {
        
        for(int j=m;j>=v[i];j--) 改成倒序的原因:f[j] 是i-1的时候更新的 如果正序的话

在i循环里遍历到 j 之前就已经遍历 j-v[i] ( j-v[i] < j )这样比较的就是 i 层的 而非 原代码

i-1 层的
        {
                
            f[j]=max(f[j],f[j-v[i]]+w[i]);
                
        }
        
    }

    printf("%d",f[m]);    f[m]表示的不止是体积为m时的最大价值,还表示所有小于m的体积中的最大价值

当 i = 1 时 所有大于 v[1] 的 f[j] 全部被赋值为 w [1] 包括 f[m] 

当 i = 2 时 若 j (m) - v[2] > v[1] 则要在 原本的 f [m-v[2]] 的初始化为 w[1] 的基础上 加上w[2] 如果不能加 则 f[m]的前半部分空着 由于倒序 f[m] 从后边填起;前面可为空;

//则若最佳解是体积为k 则 j [ m ] 是由 j[m-k] (=0) 加上j[k]得到的 (因为是从前往后添加的)

若想得到刚好体积为m的解法 只需要 除j[0]外的所有 j 都初始化为负无穷 则相加时只有m-k=0时才能加出正的结果

 
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值