第一讲 0/1背包问题


【题目来源】AcWing 2. 01背包问题

【解题思路】
每一个物品都有自己的价值和体积,我们可以用结构体数组进行存储:

struct res{
  int v, w;
} q[N];

正确输入数据:

const int N = 1050;
struct res{
  int v, w;
} q[N];
int n, V;


int main(){
  cin >> n >> V;
  for(int i = 1; i <=n ; i ++)  cin >> q[i].v >> q[i].w;
  return 0;
}

动态规划思想:

int dp[N][N];  //可能出现的最大价值为全部装下,即为1000×1000,int类型数组即可
//dp[i][j],代表当背包空间为 j 时,我面前有前 i 个物品,能够装入的最大价值

dp[i][j]分为两种情况,在dp[i - 1][j]的基础上:

①不装入第 i 个物品,dp[i - 1][j];

②装入第 i 个物品,要求当前的背包空间不小于q[i].v,dp[i - 1][j - q[i].v] + q[i].w;

这两种情况,取最大值,即状态转移方程

dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - q[i].v] + q[i].w);

memset(dp, 0, sizeof dp);  //dp数组初始化为全0或者将dp数组定义为全局变量
for(int i = 1; i <= n; i ++){  //遍历前 n 个物品
  for(int j = 0; j <= V; j ++){  //遍历0~V的空间
    dp[i][j] = dp[i - 1][j];
    if(j >= q[i].v){
      dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - q[i].v] + q[i].w);
    }
  }
}

最后答案即为,当背包空间为 V 时,我面前有前 n 个物品,能够装入的最大价值。

cout << dp[n][V];

时间复杂度: N 2 N^2 N2 + + + N N N = = = O ( O( O( n 2 n^2 n2 ) ) ) = = = 100 0 2 1000^2 10002 = = = 1 0 6 10^6 106 1000 m s 1000ms 1000ms能过;

空间复杂度: 1000 × 1000 × i n t 1000×1000×int 1000×1000×int = = = 1 0 6 10^6 106 × × × 4 B y t e 4Byte 4Byte ≈ ≈ 3.81 M B 3.81MB 3.81MB,能过。

优化:我们发现dp[i][j]的值取决于dp[i - 1][j]或dp[i - 1][j - q[i].v],即上一行同一列或上一行前列,因此可将二维数组dp[i][j]优化为dp[j],数组前面的值不变并且会决定后面的值,所以应该从后往前遍历。

for(int i = 1; i <= n; i ++){
  for(int j = V; j >= q[i].v; j --){
    dp[j] = max(dp[j], dp[j - q[i].v] + q[i].w);  //1000×int
  }
}
cout << dp[V];
  • 16
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值