01背包和完全背包问题

01背包和完全背包问题

  1. 01背包
    问题描述:背包容量为T,有n件物品,每件物品只有一个,每件物品的重量为[w[1],w[2],w[3]…w[n]],每件物品对应的价值为[v[1],v[2],v[3]…v[n]],现在要求在背包容量之内,使装入背包物品的总价值最大。
    低阶版本:
#include <iostream>
using namespace std;
int get_max(const int& x1,const int& x2)
{
    return x1>x2? x1:x2;
}
int main()
{
    int T,n;
    cin>>T>>n;
    int w[n+1];
    int v[n+1];
    for(int i=1;i<=n;++i)
    {
        cin>>w[i]>>v[i];
    }

    int dp[n+1][T+1];
    for(int i=0;i<=T;++i)
        dp[0][i]=0;
    for(int i=0;i<=n;++i)
        dp[i][0]=0;

    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=T;++j)
        {
            if(j<w[i])//如果拿不下此物品情况
                dp[i][j]=dp[i-1][j];
            else//拿的下,但是在不拿和拿之间选一个最大值
                dp[i][j]=get_max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
        }
    }
    cout<<endl;
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=T;++j)
                cout<<dp[i][j]<<" ";
        cout<<endl;
    }
    cout<<dp[n][T];
    return 0;
}

输出dp表:
输出表
优化版本:
因为求dp[i][j]时,只用到了i-1的dp值,所以可以将数组压缩到一维,使用滚动数组

#include <iostream>
using namespace std;
int get_max(const int& x1,const int& x2)
{
    return x1>x2? x1:x2;
}
int main()
{
    int T,n;
    cin>>T>>n;
    int w[n+1];
    int v[n+1];
    for(int i=1;i<=n;++i)
    {
        cin>>w[i]>>v[i];
    }

    int dp[T+1];
    for(int i=0;i<=T;++i)
    {
        dp[i]=0;
    }
    for(int i=1;i<=n;++i)
    {
        for(int j=T;j>=1;--j)
        {
            if(j<w[i])//如果拿不下此物品情况
                dp[j]=dp[j];
            else//拿的下,但是在不拿和拿之间选一个最大值
                dp[j]=get_max(dp[j],dp[j-w[i]]+v[i]);
        }
    }
    cout<<dp[T];
    return 0;
}
  1. 完全背包
    问题描述:背包容量为T,有n件物品,每件物品只有无限个,每件物品的重量为[w[1],w[2],w[3]…w[n]],每件物品对应的价值为[v[1],v[2],v[3]…v[n]],现在要求在背包容量之内,使装入背包物品的总价值最大。
    低阶版本:
#include <iostream>
using namespace std;
int get_max(const int& x1,const int& x2)
{
    return x1>x2? x1:x2;
}
int main()
{
    int T,n;
    cin>>T>>n;
    int w[n+1];
    int v[n+1];
    for(int i=1;i<=n;++i)
    {
        cin>>w[i]>>v[i];
    }

    int dp[n+1][T+1];
    for(int i=0;i<=T;++i)
        dp[0][i]=0;
    for(int i=0;i<=n;++i)
        dp[i][0]=0;

    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=T;++j)
        {
            if(j<w[i])//如果拿不下此物品情况
                dp[i][j]=dp[i-1][j];
            else//拿的下,但是在不拿和拿之间选一个最大值
                dp[i][j]=get_max(dp[i-1][j],dp[i][j-w[i]]+v[i]);
        }
    }
    cout<<endl;
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=T;++j)
                cout<<dp[i][j]<<" ";
        cout<<endl;
    }
    cout<<dp[n][T];
    return 0;
}

输出dp表:
在这里插入图片描述

优化版本:

#include <iostream>
using namespace std;
int get_max(const int& x1,const int& x2)
{
    return x1>x2? x1:x2;
}
int main()
{
    int T,n;
    cin>>T>>n;
    int w[n+1];
    int v[n+1];
    for(int i=1;i<=n;++i)
    {
        cin>>w[i]>>v[i];
    }

    int dp[T+1];
    for(int i=0;i<=T;++i)
    {
        dp[i]=0;
    }
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=T;++j)//顺序
        {
            if(j<w[i])//如果拿不下此物品情况
                dp[j]=dp[j];
            else//拿的下,但是在不拿和拿之间选一个最大值
                dp[j]=get_max(dp[j],dp[j-w[i]]+v[i]);
        }
    }
    cout<<dp[T];
    return 0;
}

终极版本:

#include <iostream>
using namespace std;
int get_max(const int& x1,const int& x2)
{
    return x1>x2? x1:x2;
}
int main()
{
    int T,n;
    cin>>T>>n;
    int w[n+1];
    int v[n+1];
    for(int i=1;i<=n;++i)
    {
        cin>>w[i]>>v[i];
    }

    int dp[T+1];
    for(int i=0;i<=T;++i)
    {
        dp[i]=0;
    }
    for(int i=1;i<=n;++i)
    {
        for(int j=w[i];j<=T;++j)//顺序,并且可以从w[i]处开始判断
        {
                dp[j]=get_max(dp[j],dp[j-w[i]]+v[i]);
        }
    }
    cout<<dp[T];
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值