01背包问题合集 蓝桥OJ

一、蓝桥OJ 1174小明的背包1 模板题

思路:

用二维数组dp判断最大价值,i表示物品数量,j表示物品体积,如果 j > V 则无需继续, j >= w 物品还能再增加,同样价值也增加,否则继承之前的价值,在之间找Max,最大价值。

#include<bits/stdc++.h>
using namespace std;

const int N = 1e3 + 4;
int dp[N][N];

int main()
{
  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
  int n, V; cin >> n >> V;
  for(int i = 1; i <= n; i++)
  {
    int w, v; cin >> w >> v;
    for (int j = 1; j <= V; j++)
    {
      if (j >= w)dp[i][j] = max(dp[i-1][j], dp[i-1][j-w] + v);
      else dp[i][j] = dp[i-1][j];
    }
  }
  cout << dp[n][V] << '\n';
  return 0;
}

优化思路:

避免新数据更新为新数据。上面的代码每次j的下标都是从小到大, 故可以直接当作一个数组,每次更新时,从后往前更新。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 4;
int dp[N];

int main()
{
  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
  int n, V; cin >> n >> V;
  for (int i = 1; i <= n; i++)
  {
      int w, v;cin >> w >> v;
      for (int j = V; j >= w; j--)
      {
        dp[j] = max(dp[j], dp[j-w]+v);
      }
  }
  cout << dp[V] << '\n';
  return 0;
}

二、蓝桥OJ 2223背包与魔法

思路:

这道题可以分成三类,1.不选 2.选但不用魔法 3.选且用魔法, 三种中取最大价值的。 

#include<bits/stdc++.h>
using namespace std;

const int N = 1e4+5;
int dp[N][2]; // 0的时候表示魔法已用,1表示魔法没用

int main()
{
  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
  int n, m, k; cin >> n >> m >> k;
  for (int i = 1; i <= n; i++)
  {
    int w, v; cin >> w >> v;
    for (int j = m; j >= 0; --j)
    {
        if (j >= w)
        {
          dp[j][0] = max(dp[j][0],dp[j-w][0]+v);
          dp[j][1] = max(dp[j][1],dp[j-w][1]+v);
        }
        if (j >= w + k)
        {
          dp[j][1] = max(dp[j][1], dp[j-w-k][0]+2*v);
        }
    }
  }
  cout << max(dp[m][0], dp[m][1]) << '\n';
  return 0;
}

三、蓝桥OJ 3741倒水

思路:

用一个二维dp数组记录所有满意度之和的最大值,dp[i][j]中的i表示1~i个客人,j表示 倒水j毫升。

分3种情况,是否倒着写要看情况:

1.当j < a时,dp[i][j] = dp[i-1][j]+e

2.当j >= a and j < c时, dp[i][j] = max(dp[i-1][j]+e, dp[i-1][j-a]+b)

3.当j>=c时, dp[i][j] = max(dp[i-1][j-c]+d , max(dp[i-1][j]+e, dp[i-1][j-a]+b))

下面的代码第一次写忘记了开long long!!!一定要记住 

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e3 + 8;
ll dp[N][N];

int main()
{
  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
  int n, m; cin >> n >> m;
  for (int i = 1; i <= n; i++)
  {
    int a, b, c, d, e;
    cin >> a >> b >> c >> d >> e;
    for (int j = 0; j <= m; j++)
    {
      if (j < a) dp[i][j] = dp[i-1][j]+e;
      else if (j >= a && j < c) dp[i][j] = max(dp[i-1][j]+e,dp[i-1][j-a]+b);
      else if (j >= c) dp[i][j] = max(dp[i-1][j-c]+d, max(dp[i-1][j]+e,dp[i-1][j-a]+b));
    }
  }
  cout << dp[n][m] << '\n';
  return 0;
}

 四、蓝桥OJ 3637盗墓分赃2

尽量把数组开大一点,不然会有测试点错误。

思路:

01背包的变形,宝藏的重量即宝藏的价值,当宝藏的重量和为奇数,一定不能平均的分成两份。后面跟01背包一样

#include<bits/stdc++.h>
using namespace std;
const int N = 2e4 + 8;
int a[N],dp[N];

int main()
{
  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
  int n;cin >> n;
  int sum = 0;
  for (int i = 1; i <= n; i++)
  {
    cin >> a[i];
    sum += a[i];
  }
  if (sum&1){
    cout << "no" << '\n';
    return 0;
  }

  sum = sum / 2;

  for (int i = 1; i <= n; i++)
  {
    for (int j = sum; j >= a[i]; j--)
    {
      dp[j] = max(dp[j],dp[j-a[i]]+a[i]);
    }
  }

  string res = (dp[sum] == sum) ? "yes": "no";
  cout << res << '\n';
  return 0;
}

五、蓝桥OJ 5118小兰的神秘礼物

跟 盗墓分赃 一模一样 

#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 8;
int x[N], dp[N];

int main()
{
  ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
  int V; cin >> V;//箱子的容量
  int n; cin >> n;//收集的小物件总数
  for (int i = 1; i <= n; i++) cin >> x[i];
  for (int i = 1; i <= n; i++)
    for (int j = V; j >= x[i]; j--) 
      dp[j] = max(dp[j],dp[j-x[i]]+x[i]);
  cout << V-dp[V] << '\n';
  return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值