动态规划:背包专题

背包专题

//这里使用f[N][N]作为dp的数组
/*val[N]表示价值,w[N]表示体积*/
typedef struct node
{
    int val;//价值
    int w;//体积
}bao;

一.01背包

01背包特点:每个物品只放一次

1.朴素写法

//模板
const int n=1003;
int f[N][N],val[N],w[N];
for(int i=1;i<=n;i++)
{
    for(int j=1;j<=v;j++)
    {
        if(j<w[i])
            f[i][j]=f[i-1][j];
       	else
           	f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+val[i]);
    }
}

2.空间优化

const int n=1003;
int f[N],val[N],w[N];
for(int i=1;i<=n;i++)
{
    for(int j=v;j>=w[i];j--)
        f[j]=max(f[j],f[j-w[i]]+val[i]);
}

二.多重背包

多重背包:每个物品放置Mi次

思路:将多重背包转化成01背包。一件价值VALi,大小Wi的可放置Mi次的物品==Mi剑价值VALi,大小Wi的只取一次的物品。

1.朴素写法

const int n=1003;
int f[N],val[N],w[N];
for(int i=1;i<=n;i++)
{
    for(int k=1;k<=m[i];k++)
    {
         for(int j=v;j>=w[i];j--)
       		 f[j]=max(f[j],f[j-w[i]]+val[i]);
	}
}

展开表达

const int N=1003;
int f[N],val[N],w[N],m[N];
int val1[N],w1[N];
int n1=0;//新值,用来表达转化后的数值

for(int i=1;i<=n;i++)
{
    for(int j=1;j<=m[i];j++)
    {
        n1++;
        w1[n1]=w[i];
        val1[n1]=val[i];
    }
}
for(int i=1;i<=n1;i++)
{
    for(int j=v;j>=w[i];j--)
    {
        f[j]=max(f[j],f[j-w1[i]]+val1[i]);
    }
}

2.二进制优化

展开表达

const int N=1003;
int f[N],val[N],w[N],m[N];
int val1[N],w1[N];
int n1=0;//新值,用来表达转化后的数值

for(int i=1;i<=n;i++)
{
    for(int j=1;m[i];j<<=1)
    {
        j=min(j,m[i]);
        m[i]=m[i]-j;
        n1++;
        w1[n1]=w[i]*j;
        val1[n1]=val[i]*j;
    }
}
for(int i=1;i<=n1;i++)
{
    for(int j=v;j>=w[i];j--)
    {
        f[j]=max(f[j],f[j-w1[i]]+val1[i]);
    }
}

朴素写法

const int n=1003;
int f[N],val[N],w[N];
for(int i=1;i<=n;i++)
{
    for(int k=1;m[i];k<<1)
    {
        k=min(k,m[i]);
        m[i]=m[i]-k;
         for(int j=v;j>=w[i];j--)
       		 f[j]=max(f[j],f[j-k*w[i]]+k*val[i]);
	}
}

三.完全背包

特点:每件物品可以无限次存放

1.转化为多重背包

Mi=V/Ci

2.逆序循环01背包

const int n=1003;
int f[N],val[N],w[N];
for(int i=1;i<=n;i++)
{
    for(int j=w[i];j<=v;j++)
        f[j]=max(f[j],f[j-w[i]]+val[i]);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风送雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值