Problem p02315 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <bits/stdc++.h>

#define LL long long
#define VI vector<int>
#define VB vector<bool>
#define VL vector<long long>
#define FOR(i, a, b) for (int i = (a); i < ((int)b); ++i)
#define RFOR(i, a) for (int i = (a); i >= 0; --i)
#define FOE(i, a) for (auto i : a)
#define ALL(c) (c).begin(), (c).end()
#define RALL(c) (c).rbegin(), (c).rend()
#define DUMP(x) cerr << #x << " = " << (x) << endl;
#define SUM(x) std::accumulate(ALL(x), 0LL)
#define MIN(v) *std::min_element(v.begin(), v.end())
#define MAX(v) *std::max_element(v.begin(), v.end())
#define EXIST(v, x) (std::find(v.begin(), v.end(), x) != v.end())
#define BIT(n) (1LL << (n))
#define UNIQUE(v) v.erase(unique(v.begin(), v.end()), v.end());
#define EPS 1e-14

const std::string YES = "YES";
const std::string Yes = "Yes";
const std::string NO = "NO";
const std::string No = "No";

bool inside(int y, int x, int H, int W) {
  return 0 <= y && y < H && 0 <= x && x < W;
}

// 4近傍（右, 下, 左, 上）
const std::vector<int> dy = {0, -1, 0, 1};
const std::vector<int> dx = {1, 0, -1, 0};

using namespace std;

int solve(int N, int W, const vector<int> &v, const vector<int> &w) {
  // dp[i][j] = i番目までみたとき、重さjで達成できる価値の最大値
  vector<vector<int>> dp(N + 1, vector<int>(W + 1, -1));
  dp[0][0] = 0;
  FOR(i, 0, N) {
    int value = v[i];
    int weight = w[i];

    FOR(j, 0, dp[0].size()) {
      if (dp[i][j] == -1) {
        continue;
      }

      dp[i + 1][j] = max(dp[i + 1][j], dp[i][j]);

      if (j + weight <= W) {
        dp[i + 1][j + weight] = max(dp[i + 1][j + weight], dp[i][j] + value);
      }
    }
  }

  int ans = 0;
  FOR(j, 0, dp[0].size()) { ans = max(ans, dp[N][j]); }

  return ans;
}

vector<vector<int>> memo;
int dfs(int i, int W, const vector<int> &v, const vector<int> &w) {
  if (i >= v.size()) {
    return 0;
  }

  if (memo[i][W] != -1) {
    return memo[i][W];
  }

  int value = v[i];
  int weight = w[i];

  // not use
  int ans = dfs(i + 1, W, v, w);

  // use
  if (W >= weight) {
    ans = max(ans, dfs(i + 1, W - weight, v, w) + value);
  }

  return memo[i][W] = ans;
}

int main() {
  int N, W;
  cin >> N >> W;
  vector<int> v(N), w(N);
  FOR(i, 0, N) { cin >> v[i] >> w[i]; }

  memo.resize(N + 1, vector<int>(W + 1, -1));
  cout << dfs(0, W, v, w) << endl;

  return 0;
}


Error: TLE

Fixed submission:

#include <algorithm>
#include <chrono>
#include <iostream>
#include <map>
#include <tuple>
#include <vector>

using namespace std;

class BranchAndBound {

public:
  vector<pair<int, int>>
      value_weight; // 効率順にソートされたアイテムの(価値, 重さ)
  const vector<int> value;  // アイテムの価値
  const vector<int> weight; // アイテムの重さ
  const int capacity;       // リュックの容量

  BranchAndBound(vector<int> value, vector<int> weight, int capacity)
      : value(value), weight(weight), capacity(capacity) {}

  int solution() {
    // 効率のいい順にソートして格納
    vector<tuple<double, int, int>> l;
    for (int i = 0; i < this->value.size(); ++i) {
      l.emplace_back(make_tuple(1.0 * this->value[i] / this->weight[i],
                                this->value[i], this->weight[i]));
    }
    sort(l.rbegin(), l.rend());

    for (auto t : l) {
      value_weight.emplace_back(make_pair(get<1>(t), get<2>(t)));
    }

    // 貪欲法で下界を求める
    int lb = initialSolution();

    return branchBoundSub(0, capacity, 0, lb);
  }

private:
  // 貪欲法
  int initialSolution() {
    int totalValue = 0;
    int rest = capacity;
    for (auto p : value_weight) {
      if (p.second <= rest) {
        totalValue += p.first;
        rest -= p.second;
      }
    }
    return totalValue;
  }

  // idx以降のアイテムを使って連続緩和した問題を解く
  double branchBoundRelax(int idx, int rest) {
    double totalValue = 0;
    for (int j = idx; j < this->value_weight.size(); ++j) {
      auto p = this->value_weight[j];
      int t = min(rest, p.second);
      totalValue += 1.0 * p.first / p.second * t;
      rest -= t;
    }
    return totalValue;
  }

  int branchBoundSub(unsigned int i, int rest, int fx, int lb) {
    if (i >= value_weight.size()) {
      return fx;
    }

    int value = value_weight.at(i).first;
    int weight = value_weight.at(i).second;

    // use i
    double u1 =
        branchBoundRelax(i + 1, rest - weight) + (weight <= rest ? value : 0);
    if (u1 + fx > lb and weight <= rest) {
      int l1 = branchBoundSub(i + 1, rest - weight, fx + value, lb);
      lb = max(lb, l1);
    }

    // not use i
    double u2 = branchBoundRelax(i + 1, rest);
    if (u2 + fx > lb) {
      int l2 = branchBoundSub(i + 1, rest, fx, lb);
      lb = max(lb, l2);
    }

    return lb;
  }
};

int main() {
  int N, W;
  cin >> N >> W;

  vector<int> v(N), w(N);
  for (int i = 0; i < N; ++i) {
    cin >> v[i] >> w[i];
  }

  BranchAndBound bb(v, w, W);
  cout << bb.solution() << endl;
}