Problem:
0-1 Knapsack Problem

You have N items that you want to put them into a knapsack. Item i has value vi and weight wi.

You want to find a subset of items to put such that:

The total value of the items is as large as possible.

The items have combined weight at most W, that is capacity of the knapsack.

Find the maximum total value of items in the knapsack.

Input

N W
v1 w1
v2 w2
:
vN wN

The first line consists of the integers N and W. In the following lines, the value and weight of the i-th item are given.

Output

Print the maximum total values of the items in a line.

Constraints

1 ≤ N ≤ 100

1 ≤ vi ≤ 1000

1 ≤ wi ≤ 1000

1 ≤ W ≤ 10000

Sample Input 1

4 5
4 2
5 2
2 1
8 3

Sample Output 1

13

Sample Input 2

2 20
5 9
4 10

Sample Output 2

9

Solution in C++11 (judge verdict: Time Limit Exceeded)

/*
  01-Knapsack Problem
     We are given a set of items with value v_i and weight w_i.
     The problem is find to a subset of items that maximize the total value
     under the total weight less than some capacity c;

  Complexity :
      Time Complexity O(n * 2^n)
      Space Complexity O(n)

   Algorithm :
     We use a branch and bound algorithm with the relaxation problem which is a continuous knapsack problem.
 */

#include <bits/stdc++.h>

using namespace std;

// ------------------------------------------8<------- start of library -------8<----------------------------------------------
template<class T>
class Knapsack {
public:
    const int size;
    vector<bool> opt_item;
    T capacity, opt_v;

    Knapsack(const int _n, const T _c) :
        size(_n), opt_item(_n, false), capacity(_c), n(0), item(_n), used(_n, false) {}
    void add_item(const int v, const int w) {
        item[n].v = v;
        item[n++].w = w;
    }

    T MaximumValue() {
        sort(item.begin(), item.end(),
             [](const Item &d1, const Item &d2) { return d1.v * d2.w > d2.v * d1.w; });

        opt_v = 0;
        for (int i = 0, w = 0; i < size; ++i) {
            if (w + item[i].w <= capacity) {
                w += item[i].w;
                opt_v += item[i].v;
                opt_item[i] = true;
            }
        }

        Rec(0, 0, 0);

        return opt_v;
    }

private:
    struct Item { T v , w; };
    int n;
    vector<Item> item;
    vector<bool> used;

    void Rec(int idx, T value, T weight) {
        if (idx == size || capacity <= weight) {
            if (weight <= capacity && opt_v < value) {
                opt_v = value;
                opt_item = used;
            }
            return ;
        }
        if (opt_v < value) {
            opt_v = value;
            opt_item = used;
        }

        // 線形緩和したときの目的関数値の計算
        double tmp_v = value, tmp_w = weight;
        int tmp_i;
        for (tmp_i = idx; tmp_w < capacity && tmp_i < size; ++tmp_i) {
            if (tmp_w + item[tmp_i].w <= capacity) {
                tmp_v += item[tmp_i].v;
                tmp_w += item[tmp_i].w;
            }
            else if (tmp_w + item[tmp_i].w == capacity) {
                // 緩和解が元の実行可能解
                tmp_v += item[tmp_i].v;
                if (opt_v < tmp_v) {
                    opt_v = tmp_v;
                    opt_item = used;
                    for (int i = idx; i <= tmp_i; ++i)
                        opt_item[i] = true;
                }
                return ;
            }
            else {
                tmp_v += item[tmp_i].v * (capacity - tmp_w) / item[tmp_i].w;
                tmp_w = capacity;
            }
        }
        if (tmp_v <= opt_v) return;

        if (weight + item[idx].w <= capacity) {
            used[idx] = true;
            Rec(idx + 1, value + item[idx].v, weight + item[idx].w);
            used[idx] = false;
        }

        Rec(idx + 1, value, weight);
    }
};
// ------------------------------------------8<------- end of library -------8<----------------------------------------------


int main() {
    cin.tie(0); ios::sync_with_stdio(false);

    int n, cap, w, v;

    cin >> n >> cap;
    Knapsack<int> kp(n, cap);
    for (int i = 0; i < n; ++i) {
        cin >> v >> w;
        kp.add_item(v, w);
    }

    cout << kp.MaximumValue() << endl;

    return 0;
}