01背包问题(动态规划DP)

本文详细介绍了01背包问题的解决方法,包括递归、记忆化搜索及多种递推写法,并提供了具体示例帮助理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题

01背包问题

有n个重量和价值分别为wi,vi的物品。从这些物品中挑选出总重量不超过W的物品,求所有挑选方案中价值总和的最大值。
1<=n<=100 
1<=wi,vi<=100
1<=W<=10000

样例输入


n=4
(w,v)={(2,3),(1,2),(3,4),(2,2)}
W=5

样例输出


7(选择0、1、3号物品)

代码

递归写法(记忆化搜索)
int n,W;
int w[MAX_N],v[MAX_N]
//记忆化数组
int dp[MAX_N+1][MAX_N+1];
//从第i个物品开始挑选总重小于j的部分
int rec(int i,int j)
{
    if(dp[i][j]>=0)
    {
        return dp[i][j];
    }
    int res;
    if(i==n)
    {
        //没有剩余物品
        res=0;
    }
    else if(j<w[i])
    {
        //无法挑选这个物品
        res=rec(i+1,j);
    }
    else
    {
        //不挑选和挑选两种情况都尝试一下
        res=max(rec(i+1,j),rec(i+1,j-w[i])+v[i]);
    }
    return dp[i][j]=res;
}
void solve()
{
    memset(dp,-1,sizeof(dp));
    printf("%d\n",rec(0,W));
}

递推写法(逆向进行)
dp[i][j]定义为从第i个物品开始挑选总重小于j的部分
dp[n][j]=0
dp[i][j]= dp[i+1][j] (j<w[i])
dp[i][j]= max(dp[i+1][j],dp[i+1][j-w[i]]+v[i]) (j>=w[i])

int n,W;
int w[MAX_N],v[MAX_N]
//DP数组
int dp[MAX_N+1][MAX_N+1];
void solve()
{
    for(int j=0;j<=W;j++)
    {
        dp[n][j]=0;
    }
    for(int i=n-1;i>=0;i--)
    {
        for(int j=0;j<=W;j++)
        {
            if(j<w[i])
            {
                dp[i][j]=dp[i+1][j];
            }
            else 
            {
                dp[i][j]=max(dp[i+1][j],dp[i+1][j-w[i]]+v[i]);
            }
        }
    }
    printf("%d\n",dp[0][W]);
}
递推写法(正向进行)
dp[i+1][j]定义为从前i个物品中选出总重量不超过j的物品时总价值的最大值
dp[0][j]=0
dp[i+1][j]=dp[i][j] (j<w[i])
dp[i+1][j]=max(dp[i][j],dp[i][j-w[i]]+v[i]) (j>=w[i])
int n,W;
int w[MAX_N],v[MAX_N]
//DP数组
int dp[MAX_N+1][MAX_N+1];
void solve()
{
    for(int j=0;j<=W;j++)
    {
        dp[0][j]=0;
    }
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<=W;j++)
        {
            if(j<w[i])
            {
                dp[i+1][j]=dp[i][j];
            }
            else 
            {
                dp[i+1][j]=max(dp[i][j],dp[i][j-w[i]]+v[i]);
            }
        }
    }
    printf("%d\n",dp[n][W]);
}
状态转移
从“前i个物品中选取总重不超过j时的状态”向“前i+1个物品中选取总重不超过j”和“前i+1个物品中选取总重不超过j+w[i]时的状态”的转移。
int n,W;
int w[MAX_N],v[MAX_N]
//DP数组
int dp[MAX_N+1][MAX_N+1];
void solve()
{
    memset(dp,0,sizeof(dp));
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<=W;j++)
        {
            dp[i+1][j]=max(dp[i+1][j],dp[i][j]);
            if(j+w[i]<=W)
            {
                dp[i+1][j+w[i]]=max(dp[i+1][j+w[i]],dp[i][j]+v[i]);
            }
        }
    }
    printf("%d\n",dp[n][W]);
}
注:文章内容源于《挑战程序设计竞赛》(第二版)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值