动态规划之0-1 背包问题

问题描述:有n种物品,每种只有一个。第i种物品的体积为Vi,重量为Wi。挑选若干物品装到一个容量为C的背包中,使得背包内物品在总体积不超过C的前提下重量尽可能大。
ps:容量对应体积
1<=n<=100, 1<=Vi<=C<=10000,1<=Wi<=10^6


#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <vector>
 using namespace std;
#define LL long long

// input
// 1
// 3 10
// 4 3 5
// 10 1 6
//
// output
// Case #1: 16

 int n;        // 物品个数
 int cpacity;  //背包总容量
 int ans;      //所求的最大重量

 int weights[1005];   //物品的重量数组
 int volumes[1005];   //物品的体积数组
 int dp[1005][1005];  //计算最大重量的动态规划数组

 void solve1() {
  // 法1
  // dp[i][j]
  //表示在背包容量为j时,放入第i,i+1,...n个物品时的最大重量
  // i 逆序枚举,但 j的循环次序是无关重要的
  for (int i = n; i >= 1; i--) {
    for (int j = 0; j <= cpacity; j++) {
      dp[i][j] =
          (i == n ? 0 : dp[i + 1][j]);  //不放入第一个物品时,dp[i][j]至少等于
      // dp[i+1][j]

      if (j >= volumes[i]) {
        //  dp[i + 1][j - volumes[i]] 表示放入背包容量为j -
        //  volumes[i],放入第i+1,i+2,..n个物品时的最大重量。
        dp[i][j] = max(dp[i][j], dp[i + 1][j - volumes[i]] + weights[i]);
      }
    }
  }

  ans = dp[1][cpacity];
}

 void solve2() {
  // 法1
  // dp[i][j]
  //表示在背包容量为j时,放入第1,2,...,i个物品时的最大重量
  // i 顺序枚举

  for (int i = 1; i <= n; i++) {
    for (int j = 0; j <= cpacity; j++) {
      dp[i][j] = (i == 1 ? 0 : dp[i - 1][j]);
      if (j > volumes[i]) {
        dp[i][j] = max(dp[i][j], dp[i - 1][j - volumes[i]] + weights[i]);
      }
    }
  }
  ans = dp[n][cpacity];
}

 void sovle3() {
  // 紧接solve2 思路,用一维滚动数组节省空间
  int f[1005];
  memset(f, 0, sizeof(f));
  for (int i = 1; i <= n; i++) {
    for (int j = cpacity; j >= 0; j--) {
      if (j >= volumes[i]) {
        f[j] = max(f[j], f[j - volumes[i]] + weights[i]);
      }
    }
  }

  ans = f[cpacity];
}

 int main() {
  freopen(
      "/Users/yuxiao/XcodeProject/DynamicalProgramming/DynamicalProgramming/in",
      "r", stdin);
  freopen(
      "/Users/yuxiao/XcodeProject/DynamicalProgramming/DynamicalProgramming/"
      "out",
      "w", stdout);
  int T, t;
  t = 1;
  cin >> T;
  while (T--) {
    ans = 0;
    memset(dp, 0, sizeof(dp));
    cin >> n >> cpacity;

    // 注意下标从1开始
    for (int i = 1; i <= n; i++) {
      cin >> volumes[i];
    }
    for (int i = 1; i <= n; i++) {
      cin >> weights[i];
    }
    //    solve2();
    sovle3();
    cout << "Case #" << t++ << ": " << ans << endl;
  }
  return 0;
}

Uva 练习题 12563 - Jin Ge Jin Qu hao

https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=847&problem=4008&mosmsg=Submission+received+with+ID+17975054

// 0-1背包问题
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <string>
#include <vector>
using namespace std;
#define LL long long

int n;
LL t;
int songs[51];

int main() {
  //  freopen(
  //      "/Users/yuxiao/XcodeProject/DynamicalProgramming/DynamicalProgramming/in",
  //      "r", stdin);
  //  freopen(
  //      "/Users/yuxiao/XcodeProject/DynamicalProgramming/DynamicalProgramming/"
  //      "out",
  //      "w", stdout);

  int T, caseN;
  cin >> T;
  caseN = 1;
  LL ans;
  LL totalLen;
  while (T--) {
    totalLen = 0;
    ans = 0;
    cin >> n >> t;
    for (int i = 1; i <= n; i++) {
      cin >> songs[i];
    }
    LL res[t];

    LL totalLengths[t];
    memset(res, -1, sizeof(res));
    memset(totalLengths, 0, sizeof(totalLengths));
    // res[j] 代表歌曲总时长刚好为j的歌曲最多个数
    res[0] = 0;
    for (int i = 1; i <= n; i++) {
      for (LL j = t - 1; j >= 1; j--) {
        if (j >= songs[i] && res[j - songs[i]] >= 0) {
          res[j] = max(res[j], res[j - songs[i]] + 1);
          ans = max(ans, res[j]);
          //          totalLengths[j] =
          //              max(totalLengths[j], totalLengths[j - songs[i]] +
          //              songs[i]);
        }
      }
    }
    //    ans = res[t - 1];
    for (LL k = t - 1; k >= 1; k--) {
      if (ans == res[k]) {
        totalLen = k;
        break;
      }
    }
    totalLen = totalLen + 678;
    ans += 1;
    printf("Case %d: %lld %lld\n", caseN++, ans, totalLen);
  }
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值