/*
    Author: Shivam Shukla
    Title : DP_E_Mod.cpp
    Date : 25/08/2020   >> 17:15:20

    KnapSack 2 AtCoder Explanation and Intuition of thinking.

    This is somewhat modified Knapsack problem in terms of constraints on the weights. In the
    original, classic version of the problem it is the weight whose constraints are pretty lower
    and in the range of memory that can be occupied. 

    While in case of the Knapsack 2, the weight may reach upto a total of 1e9 as well as the individual
    weights can reach the same bounds. Now the problem is that in the original version of the Knapsack
    problem, the DP states were :

    1. Current Weight (say i)
    2. Current Number of Items Seen (say j)

    Now if we create a state based on the weights then the total amount of memory required asymptotically 
    will be equivalent to, O(Total Weight * Total Items) = O(N * W).

    In this case it would reach to the actual values of  1e11, which is just 1e5 times what memory can 
    actually be allocated for the program. Now the things are such that we cannot use the weights into 
    our DP state. This DP state would be discarded for the efficiency of the program as well. 

    Now here comes the things on the table where we need to think of the option to replace this state'
    and get some better state, so now consider the same reasoning that we are provided with the weight 
    and values for each of them. Consider we want to find out what is the maximum value obtainable using all
    of this, 

    Brute Force Approach:

    The brute force isn't gonna change for this problem since the problem is all the same and the bute force
    need no optoimization since it deals with the subsets and not the weights and values. It concerns 
    itself with the subset of the items and not the values or the weights.

    Efficient Approach :

    This is where we want an optimization since both our time and space asymptotic complexities
    are too much higher for the problem solution to be accepted. Now we think of something better.

    Looking at the constraints, the item value constraints are uin pretty good and smaller range. 
    It is equivalent to 1e3, which is pretty better and our number of items is closer to 100.

    So into the worst case when all the items are summed and they sum up with the smaller value than W, 
    then all the value will be used and it will become, 1e5 (1e3 * 1e2).

    Now this gives some insights about in which direction we must think of and conscribe ourselves, the 
    things are pretty similar but just the state gives different vibes and meaning now. 

    In previous case, we found out the maximum value we can obtain provided weight sum of i and number of
    items be j, then the each DP state gave us the maximum value we can obtain with that. In this case, 
    it is like, can we get this value using weights provided to us ?

    Provided the number of weights and value what is the minimum weight we can obtain for this value?
    Then we will examine which highest value follows the constraints on weight.

    Once we find that value it will be the best possible answer we can get.

    Now let us think in particular way to do the things.

    Consider we are at the value v, do we need the number of items we are considering ? 
    Yes we need it since it will be the variable which will decide whether we will take this weight.

    So in order to find the least weight possible weight for the value v, we need to states to identify
    the state distinctly. 

    1. Number of weights we have seen so far (Current item under consideration)
    2. Value (Current value)

    These two states would lead us to the minimum weight we can get for the given configurations.
    So the problem now after creating the states will be pretty intuitive.


    Lets think about these values. What is feasibility of this value to exist ? What decides the minimum 
    weight we can get at this weight? This value for sure would be composed up of multiple such weights. 

    If previous weights (before current) would be optimized for the least weight possible and then we
    can either choose this current item (n) or reject it (same as that of Knapsack isn't it?) well for the part
    of each item the things are not gonna change. We can always either choose an item or not choose it.

    Consider the possibilities,

    1. If we have chosen it, now if we have decided to choose it then we need to solve the same problem 
    of finding the minimum weight by using the total value = (v - val[i]), but with the number of items = (j - 1).

    solve(n, v) = wt[n] + solve(n - 1, v - v[n]) 

    But here is a catch, the value we are subtracting from the v (our current value must be smaller than v) 
    other wise it would be absurd to think of it.

    2. If we don't chose it, so if we decided to not choose it then we would be trying to find the
    minimum weight having the sum of values v and number of items (n - 1).

    solve(n, v) = solve(n - 1, v)

    Now we can clearly see the possibility of the things and property that a bigger problem is solved 
    using the smaller subproblems. These subproblems constitute the answer for the actual problem. 

    This property is called Optimal Substructure.

    But the things aren't always so simple yet the solution posed above is expoenential in its runtime 
    complexity. In order to better solve this we need to think of some better optimizations. 

    In this case in particular if we see that there are multiple repetitions of the state, consider we 
    are solving the problem for (n - 5, v - 16) then think simply what can happen, there will be multiple times
    this thing may come up 5 items having the sum of 16, with all those big problem configurations
    this state or call of function would always be involved.

    If it is so, then we are actually doing an overkill by computing this thing multiple times. 
    This is a very important hallmark of the very popular programming pradigm - Dynamic Programming.

    This very property is called Overlapping Subproblems. 


    SInce this problem can be evidently solved using the DP, now since it follows both of the hallmarks 
    of the paradigm, namely.

    1. Optimal Subtructure
    2. Overlapping Subproblems.

    Due to both of these props the things are pretty simpler and easier to think in the terms of DP states,

    1. Number of items
    2. Value being examined.

    For each such configuration we will be maintaining the minimum weight we can obtain by using the 
    items n, and total values v.

    Now the DP state can be written in terms of the smaller subproblems using the smaller states.

    dp[n][v] = min(dp[n - 1][v], (v >= val[n]) ? wt[n] + dp[n - 1][v - val[n]] : INF(ll));

    for the base cases like what happens if the value is 0, so we can actually require no weights in
    order to get the value 0 while if the number of items considered is 0, then the maximum weight we can 
    get is 0. 

    Other than that the DP states will be driven by the above state changes.
*/

#include<bits/stdc++.h>
using namespace std;
 
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef vector<pii> vpii;
typedef vector<pair<ll,ll> > vpll;
 
const int MOD=1e9+7;
const int MAX=1e5+5;
const double PI= acos(-1.0);
const long double EPS=1e-10;
const int64_t INF=1e18+10;
 
#define fastio() ios_base::sync_with_stdio(false);cin.tie(0), cout.tie(0)
#define trace(...) " [" << #__VA_ARGS__ ": " << (__VA_ARGS__) << "] "
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define vi vector<int>
#define vl vector<ll>
#define vs vector<str>
#define vc(x) vector<x>
#define mapll map<ll,ll>
#define mapib map<int,bool>
#define mapiv map<int,vector>
#define mapsi map<string,int>
#define rep(i,j,k) for(ll i=j;i<k;i++)
#define down(i,j,k) for(ll i=j;i>=k;i--)
#define repa(i,n) for(ll i=0;i<n;i++)
#define dowa(i,n) for(ll i=n;i>=0;i--)
#define reps(i,j,k,s) for(ll i=j;i<k;i+=s)
#define downs(i,j,k,s) for(ll i=j;i>=k;i-=s)
#define trv(i,x) for(auto i:x)
#define pb push_back
#define eb emplace_back
#define sz(x) (int)x.size()
#define ff first
#define ss second
#define str string 
#define dub double
#define pqmax priority_queue<ll>
#define pqmin priority_queue<ll,vl,greater<ll> >
#define INF(x) numeric_limits<x>::max()
 
template<typename t> t lcm(t a, t b) {return (a*b)/__gcd(a,b);}
template<typename t> t gcd(t a, t b) {return __gcd(a,b);}
template<typename t> t mul_mod(t a, t b, t m){t res=((a%m)*(b%m)%m); return res;}
template<typename t> t add_mod(t a, t b, t m){t res=((a%m)+(b%m))%m; return res;}
template<typename t> t pow_mod(t a,t b,t m) {t res=1;while(b){if(b&1) res=mul_mod(res,a,m);a=mul_mod(a,a,m), b>>=1;} return res%m;}
template<typename t> vc(t) num_vec(t num) {t res; while (num) res.pb(num%10), num/=10; return res;}
template<typename t> t vec_num(t vec) {t res=0; ll mul=1; repa(i,sz(vec)) res=vec[i]*mul, mul*=10; return res;}
 

int32_t main(int argc,char** argv){
    fastio();
    auto tstart= clock();
 
    #ifndef ONLINE_JUDGE
      freopen("input.txt","r",stdin);
      freopen("output.txt","w",stdout);
      freopen("error.txt","w",stderr);
    #endif   

    int n, w; cin >> n >> w;
    vpll a(n); repa(i, n) cin >> a[i].ff >> a[i].ss;

    ll maxVal = 0;
    repa(i, n)
        maxVal += a[i].ss;

    vc(vl) dp(n + 1, vl(maxVal + 1));

    repa(i, n + 1)
        dp[i][0] = 0;

    rep(i, 1, maxVal + 1)
        dp[0][i] = 1e18;

    ll ans = -INF(ll);
    rep(i, 1, n + 1) {
        rep(j, 1, maxVal + 1) {
            dp[i][j] = min(dp[i - 1][j], (a[i - 1].ss <= j) ? a[i - 1].ff + dp[i - 1][j - a[i - 1].ss] : INF(ll));
            if (dp[i][j] <= w && dp[i][j] > 0)
                ans = j;
        }
    }
    cout << ans << endl;

    cerr << setprecision(2) << fixed<<"Time elapsed: " << (double)(clock() - tstart)/CLOCKS_PER_SEC << endl; 
    return 0; 
}

Measured memory_bytes: 83148