CodeEff/ECCO huggingface dataset:
# Original solution
import sys
input=sys.stdin.readline
from collections import defaultdict as dd
n,w=list(map(int,input().split()))
we=[0]*n
val=[0]*n
for i in range(n):
  ww,v=list(map(int,input().split()))
  we[i]=ww
  val[i]=v
dp=dd(lambda:-1)
def solve(i,w,we,val):
  if(i==0 or w==0):
    return 0
  if(dp[(i,w)]!=-1):
    return dp[(i,w)]
  if(we[i-1]<=w):
    if(dp[(i-1,w-we[i-1])]!=-1):
      x=dp[(i-1,w-we[i-1])]
    else:
      x=dp[(i-1,w-we[i-1])]=solve(i-1,w-we[i-1],we,val)
    if(dp[(i-1,w)]!=-1):
      y=dp[(i-1,w)]
    else:
      y=dp[(i-1,w)]=solve(i-1,w,we,val)
    dp[(i,w)]=max(val[i-1]+x,y)
    return dp[(i,w)]
  else:
    if(dp[(i-1,w)]!=-1):
      y=dp[(i-1,w)]
    else:
      y=dp[(i-1,w)]=solve(i-1,w,we,val)
    dp[(i,w)]=y
    return dp[(i,w)]
print((solve(n,w,we,val)))
#print(dp)  


# Optimized solution
import sys
input=sys.stdin.readline
from collections import defaultdict as dd
n,w=list(map(int,input().split()))
maxn=10000000000000000
we=[0]*n
val=[0]*n
su=0
for i in range(n):
    ww,v=list(map(int,input().split()))
    we[i]=ww
    val[i]=v
    su+=v
dp=[maxn]*(su+1)
dp[0]=0
for i in range(n):
    for j in range(su-val[i],-1,-1):
        dp[j+val[i]]=min(dp[j+val[i]],we[i]+dp[j])
ans=0
for i in range(len(dp)):
    if(dp[i]<=w):
        ans=max(ans,i)
print(ans)
# Original solution
import itertools,sys
def LI(): return list(map(int,sys.stdin.readline().rstrip().split()))
N,W = LI()
wv = [LI() for _ in range(N)]
V = N*10**3
dp = [[float('INF')]*(V+1) for _ in range(N+1)]
dp[0][0] = 0
for i,j in itertools.product(list(range(1,N+1)),list(range(V+1))):
    w,v = wv[i-1]
    if j-v>=0:
        dp[i][j] = min(dp[i][j],dp[i-1][j-v]+w)
    dp[i][j] = min(dp[i][j],dp[i-1][j])
ans = 0
for k in range(V+1):
    if dp[-1][k]<=W:
        ans = max(ans,k)
print(ans)


# Optimized solution
import itertools,sys
def LI(): return list(map(int,sys.stdin.readline().rstrip().split()))
N,W = LI()
wv = [LI() for _ in range(N)]
V = N*10**3
dp = [[float('INF')]*(V+1) for _ in range(N+1)]
dp[0][0] = 0
for i,j in itertools.product(list(range(1,N+1)),list(range(V+1))):
    w,v = wv[i-1]
    if j-v>=0 and dp[i-1][j-v]+w<=W:
        dp[i][j] = min(dp[i][j],dp[i-1][j-v]+w)
    dp[i][j] = min(dp[i][j],dp[i-1][j])
print((max([i for i in range(V+1) if dp[-1][i]<=W])))
# Original solution
import itertools,sys
def LI(): return list(map(int,sys.stdin.readline().rstrip().split()))
N,W = LI()
wv = [LI() for _ in range(N)]
V = 10**5
dp = [[float('INF')]*(V+1) for _ in range(N+1)]
dp[0][0] = 0
for i,j in itertools.product(list(range(1,N+1)),list(range(V+1))):
    w,v = wv[i-1]
    if j-v>=0 and dp[i-1][j-v]+w<=W:
        dp[i][j] = min(dp[i][j],dp[i-1][j-v]+w)
    dp[i][j] = min(dp[i][j],dp[i-1][j])
print((max([i for i in range(V+1) if dp[-1][i]<=W])))


# Optimized solution
import sys
def LI(): return list(map(int,sys.stdin.readline().rstrip().split()))
N,W = LI()
wv = [LI() for _ in range(N)]
V = N*10**3
dp = [[float('INF')]*(V+1) for _ in range(N+1)]
dp[0][0] = 0
for i in range(1,N+1):
    w,v = wv[i-1]
    for j in range(V+1):
        if j-v>=0 and dp[i-1][j-v]+w<=W:
            dp[i][j] = min(dp[i][j],dp[i-1][j-v]+w)
        dp[i][j] = min(dp[i][j],dp[i-1][j])
print((max([i for i in range(V+1) if dp[-1][i]<=W])))
# Original solution
n,w=list(map(int,input().split()))
dp=[999999999999999]*(100001)
dp[0]=0
for i in range(n):
	wt,val=list(map(int,input().split()))
	for j in range(100000,val-1,-1):
		dp[j]=min(dp[j],dp[j-val]+wt)
for i in range(100000,-1,-1):
	if dp[i]<=w:
		print(i)
		exit()

# Optimized solution
n,w=list(map(int,input().split()))
l=(n*1000)+1
dp=[9999999999]*(l)
dp[0]=0
for i in range(n):
	wt,val=list(map(int,input().split()))
	for j in range(l-1,val-1,-1):
		dp[j]=min(dp[j],dp[j-val]+wt)
for i in range(l-1,-1,-1):
	if dp[i]<=w:
		print(i)
		exit()
# Original solution
import sys
from collections import Counter, deque, defaultdict
from itertools import accumulate, permutations, combinations, takewhile, compress, cycle
from functools import reduce
from math import ceil, floor, log10, log2, factorial
from pprint import pprint

sys.setrecursionlimit(1000000)
# MOD = 10 ** 9 + 7
# N = int(input())
# A = [int(x) for x in input().split()]
# V = [[0] * 100 for _ in range(100)]
# A = [int(input()) for _ in range(N)]

N, W = [int(x) for x in input().split()]

dp = [float('inf')] * 1000 * 100*10
vs = set()
vs.add(0)
dp[0] = 0

for i in range(N):
    w, v = [int(x) for x in input().split()]

    tmpDP = dp.copy()
    for vv in list(vs):
        if dp[vv + v] > dp[vv] + w:
            tmpDP[vv + v] = dp[vv] + w
            vs.add(vv + v)
    dp = tmpDP


ans = 0
for v in list(vs):
    if dp[v] <= W:
        ans = max(ans, v)
print(ans)


# Optimized solution
import sys
from collections import Counter, deque, defaultdict
from itertools import accumulate, permutations, combinations, takewhile, compress, cycle
from functools import reduce
from math import ceil, floor, log10, log2, factorial
from pprint import pprint

sys.setrecursionlimit(1000000)
# MOD = 10 ** 9 + 7
# N = int(input())
# A = [int(x) for x in input().split()]
# V = [[0] * 100 for _ in range(100)]
# A = [int(input()) for _ in range(N)]

N, W = [int(x) for x in input().split()]

dp = defaultdict(lambda: float('inf'))
dp[0] = 0

for i in range(N):
    w, v = [int(x) for x in input().split()]

    add = defaultdict(lambda: float('inf'))
    for vv in list(dp.keys()):
        if dp[vv + v] > dp[vv] + w:
            add[vv + v] = dp[vv] + w
    dp.update(add)

print((max([i for i in list(dp.items()) if i[1] <= W], key=lambda x:x[0])[0]))
# Original solution
import sys
input = sys.stdin.readline

N, W = [int(x) for x in input().split()]
wv = []
for _ in range(N):
    wv.append([int(x) for x in input().split()])
V = 10 ** 5
inf = float("inf")

dp = [[inf] * (V + 1) for _ in range(N + 1)]
dp[0][0] = 0
ans = -1

for i in range(N):
    for j in range(V + 1):
        w, v = wv[i]
        if j >= v:
            dp[i + 1][j] = min(dp[i][j], dp[i][j - v] + w)
        else:
            dp[i + 1][j] = dp[i][j]
        if dp[i + 1][j] <= W:
            ans = max(ans, j)
print(ans)

# Optimized solution
import sys
input = sys.stdin.readline

n, W = [int(x) for x in input().split()]
wv = [[int(x) for x in input().split()] for _ in range(n)]

dp = [[float('inf')] * (10**5 + 1) for _ in range(n + 1)]
dp[0][0] = 0

for i in range(1, n + 1):
    w, v = wv[i - 1]
    for j in range(10**5 + 1):
        if j - v >= 0:
            dp[i][j] = min(dp[i - 1][j], dp[i - 1][j - v] + w)
        else:
            dp[i][j] = dp[i - 1][j]

ans = 0

for i in range(10**5 + 1):
    if dp[-1][i] <= W:
        ans = max(ans, i)

print(ans)
# Original solution
N, W = list(map(int, input().split()))
WV = [list(map(int, input().split())) for _ in range(N)]

#import math
INF = 10 ** 12 # math.inf
V = 10 ** 5 + 10

dp = [[INF] * V for _ in range(N + 1)]
dp[0][0] = 0

for i, (w, v) in enumerate(WV):
	for n in range(V):
		if v <= n:
			dp[i + 1][n] = min(dp[i + 1][n], dp[i][n - v] + w)
		dp[i + 1][n] = min(dp[i + 1][n], dp[i][n])
"""
for line in dp:
	for cell in line:
		if cell == INF:
			print("  INF", end="")
		else:
			print("{:5d}".format(cell), end="")
	print()
"""
r = 0
for i in range(V):
	if dp[-1][i] <= W:
		r = i
print(r)

# Optimized solution
N, W = list(map(int, input().split()))
WV = [list(map(int, input().split())) for _ in range(N)]

INF = 10 ** 12
V = 10 ** 3 * 100 + 10

dp = [0] + [INF] * V
for w, v in WV:
	for i in range(V, v - 1, -1):
		dp[i] = min(dp[i], dp[i - v] + w)

r = 0
for i in range(V):
	if dp[i] <= W:
		r = i
print(r)

"""
for cell in dp:
	if cell == INF:
		print("  INF", end="")
	else:
		print("{:5d}".format(cell), end="")
print()
"""
# Original solution
N, W = list(map(int, input().split()))
WV = [list(map(int, input().split())) for _ in range(N)]

INF = 10 ** 12
V = 10 ** 3 * 100 + 10

dp = [0] + [INF] * V
for w, v in WV:
	for i in range(V, v - 1, -1):
		dp[i] = min(dp[i], dp[i - v] + w)

r = 0
for i in range(V):
	if dp[i] <= W:
		r = i
print(r)

"""
for cell in dp:
	if cell == INF:
		print("  INF", end="")
	else:
		print("{:5d}".format(cell), end="")
print()
"""


# Optimized solution
N, W = list(map(int, input().split()))
WV = [list(map(int, input().split())) for _ in range(N)]

INF = 10 ** 12
MAX_V = 10 ** 5 + 10
dp = [INF] * MAX_V
dp[0] = 0

for w, v in WV:
	for i in range(MAX_V - 1, v - 1, -1):
		dp[i] = min(dp[i], dp[i - v] + w)
	#print(dp)

max_v = 0
for v, w in enumerate(dp):
	if w <= W:
		max_v = max(max_v, v)
print(max_v)
# Original solution
import math
import fractions
import bisect
import collections
import itertools
import heapq
import string
import sys
import copy
from collections import deque
sys.setrecursionlimit(10**7)
def gcd(a,b):return fractions.gcd(a,b) #最大公約数
def lcm(a,b):return (a*b) // fractions.gcd(a,b) #最小公倍数
def iin(): return int(eval(input())) #整数読み込み
def isn(): return input().split() #文字列読み込み
def imn(): return list(map(int, input().split())) #整数map取得
def iln(): return list(map(int, input().split())) #整数リスト取得
def iln_s(): return sorted(iln()) # 昇順の整数リスト取得
def iln_r(): return sorted(iln(), reverse=True) # 降順の整数リスト取得
def join(l, s=''): return s.join(l) #リストを文字列に変換
def perm(l, n): return itertools.permutations(l, n) # 順列取得
def perm_count(n, r): return math.factorial(n) // math.factorial(n-r) # 順列の総数
def comb(l, n): return itertools.combinations(l, n) # 組み合わせ取得
def comb_count(n, r): return math.factorial(n) // (math.factorial(n-r) * math.factorial(r)) #組み合わせの総数

N,W = imn()
max_v = 100001
wv = [iln() for _ in range(N)]
max_w = 10**10
dp = [[max_w for _ in range(max_v+1)] for _ in range(N+1)]
dp[0][0] = 0
for i in range(N):
    for sum_v in range(max_v):
        if sum_v - wv[i][1] >= 0:
            dp[i+1][sum_v] = min(dp[i+1][sum_v], dp[i][sum_v-wv[i][1]]+wv[i][0])
        dp[i+1][sum_v] = min(dp[i+1][sum_v], dp[i][sum_v])

ans = 0
for sum_v in range(max_v):
    if dp[N][sum_v] <= W: ans = sum_v
print(ans)

# Optimized solution
import math
import fractions
import bisect
import collections
import itertools
import heapq
import string
import sys
import copy
from collections import deque
sys.setrecursionlimit(10**7)
def gcd(a,b):return fractions.gcd(a,b) #最大公約数
def lcm(a,b):return (a*b) // fractions.gcd(a,b) #最小公倍数
def iin(): return int(eval(input())) #整数読み込み
def ifn(): return float(eval(input())) #浮動小数点読み込み
def isn(): return input().split() #文字列読み込み
def imn(): return list(map(int, input().split())) #整数map取得
def fmn(): return list(map(float, input().split())) #浮動小数点map取得
def iln(): return list(map(int, input().split())) #整数リスト取得
def iln_s(): return sorted(iln()) # 昇順の整数リスト取得
def iln_r(): return sorted(iln(), reverse=True) # 降順の整数リスト取得
def fln(): return list(map(float, input().split())) # 浮動小数点リスト取得
def join(l, s=''): return s.join(l) #リストを文字列に変換
def perm(l, n): return itertools.permutations(l, n) # 順列取得
def perm_count(n, r): return math.factorial(n) // math.factorial(n-r) # 順列の総数
def comb(l, n): return itertools.combinations(l, n) # 組み合わせ取得
def comb_count(n, r): return math.factorial(n) // (math.factorial(n-r) * math.factorial(r)) #組み合わせの総数
def two_distance(a, b, c, d): return ((c-a)**2 + (d-b)**2)**.5 # 2点間の距離
MOD = 10**9+7

N,W = imn()
wv = [iln() for _ in range(N)]
max_v = 10**3*100+1

dp = [[10**10 for _ in range(max_v)] for _ in range(N+1)]
dp[0][0] = 0

for i in range(N):
    for sum_v in range(max_v):
        if wv[i][1] <= sum_v: 
            dp[i+1][sum_v] = min(dp[i+1][sum_v], dp[i][sum_v-wv[i][1]]+wv[i][0])
        dp[i+1][sum_v] = min(dp[i+1][sum_v], dp[i][sum_v])
ans = 0
for v in range(max_v):
    if dp[N][v] <= W: ans = v
print(ans)
# Original solution
N, W = list(map(int, input().split()))
dp = [[W+1]*(100000+1) for _ in range(N+1)]
dp[0][0] = 0
for i in range(N):
    w, v = list(map(int, input().split()))
    for j in range(100000+1):
        if j+v <= 100000:
            dp[i+1][j+v] = min(dp[i+1][j+v], dp[i][j] + w)
        dp[i+1][j] = min(dp[i+1][j], dp[i][j])
i = -1
while True:
    if dp[N][i] <= W:
        print((100000+1+i))
        break
    else:
        i -= 1

# Optimized solution
INF_V = 1000*100
N, W = list(map(int, input().split()))
dp = [[W+1]*(INF_V+1) for _ in range(N+1)]
dp[0][0] = 0
for i in range(N):
    w, v = list(map(int, input().split()))
    for j in range(INF_V-1000+1):
        dp[i+1][j+v] = min(dp[i+1][j+v], dp[i][j] + w)
        dp[i+1][j] = min(dp[i+1][j], dp[i][j])
print(([i for (i, w) in enumerate(dp[N]) if w <= W][-1]))
# Original solution
MAX_INT = int(10e10)

N,W = list(map(int,input().split()))
w = [0]
v = [0]

for i in range(N):
  a,b = list(map(int,input().split()))
  w.append(a)
  v.append(b)
V_MAX = max(v)

# dp[i][v] = w
dp = [[MAX_INT]*(N*V_MAX+1) for i in range(N+1)]

for i in range(1,N+1):
  dp[i-1][v[i-1]] = w[i-1]
  for j in range(1,N*V_MAX+1):
    if j < v[i]:
      dp[i][j] = dp[i-1][j]
    else:
      dp[i][j] = min(dp[i-1][j], dp[i-1][j-v[i]]+w[i])  # max(iの品を使わない時, iの品を使う時)
for j in range(N*V_MAX,0,-1):
  for i in range(1,N+1):
    if dp[i][j] <= W:
      print(j)
      exit()


# Optimized solution
MAX_INT = int(10e10)

N,W = list(map(int,input().split()))
w = [0]
v = [0]

for i in range(N):
  a,b = list(map(int,input().split()))
  w.append(a)
  v.append(b)
V_MAX = max(v)

# dp[i][v] = w
dp = [[MAX_INT]*(N*V_MAX+1) for i in range(N+1)]

for i in range(N+1):
  dp[i][v[i]] = w[i]
for i in range(1,N+1):
  for j in range(1,N*V_MAX+1):
    if j < v[i]:
      dp[i][j] = dp[i-1][j]
    else:
      dp[i][j] = min(dp[i-1][j], dp[i-1][j-v[i]]+w[i],dp[i][j])  # max(iの品を使わない時, iの品を使う時)
for j in range(N*V_MAX,0,-1):
  for i in range(1,N+1):
    if dp[i][j] <= W:
      print(j)
      exit()
# Original solution
def solve():
    N, W = list(map(int, input().split()))
    MAX_V = 100100
    MAX_N = 110
    w = []
    v = []
    for i in range(N):
        tmpw, tmpv = list(map(int, input().split()))
        w.append(tmpw)
        v.append(tmpv)

    dp = [[float('inf') for i in range(MAX_V+1)] for j in range(MAX_N+1)]

    dp[0][0] = 0

    for i in range(N):
        for sum_v in range(MAX_V):
            if sum_v - v[i] >= 0:
                dp[i+1][sum_v] = min(dp[i+1][sum_v], dp[i][sum_v - v[i]] + w[i])
            
            dp[i+1][sum_v] = min(dp[i+1][sum_v], dp[i][sum_v])
        
    res = 0
    for sum_v in range(MAX_V+1):
        if dp[N][sum_v] <= W:
            res = sum_v
    print(res)

if __name__ == '__main__':
    solve()

# Optimized solution
def solve():
    n, w = list(map(int, input().split()))
    l = [list(map(int, input().split())) for i in range(n)]

    lim = n * 10 ** 3 + 1
    dp = [[10**15 for i in range(lim)] for i in range(n+1)]

    for i in range(n+1):
        dp[i][0] = 0

    for i in range(n):
        for sum_v in range(lim):
            if sum_v-l[i][1]>=0:
                dp[i+1][sum_v] = min(dp[i+1][sum_v], dp[i][sum_v - l[i][1]] + l[i][0])
            dp[i+1][sum_v] = min(dp[i+1][sum_v], dp[i][sum_v])

    ans = 0
    for sum_v in range(lim):
        if dp[n][sum_v] <= w:
            ans = sum_v

    print(ans)

if __name__ == '__main__':
    solve()
# Original solution
N,W = list(map(int,input().split()))
WV = [[0,0]] + [list(map(int,input().split())) for _ in range(N)]
vrng = (10**3)*N+1
dp = [[float('inf') for _ in range(vrng)] for _ in range(N+1)]
dp[0][0] = 0
for i in range(1, N+1):
  tmpw, tmpv = WV[i]
  for j in range(vrng):
    if j-tmpv>=0:
      dp[i][j] = min(dp[i-1][j],dp[i-1][j-tmpv]+tmpw)
    else:
      dp[i][j] = dp[i-1][j]

ans = -float('inf')
for row in dp:
  for j,w in enumerate(row):
    if w<=W and ans<j:
      ans = j
print(ans)

# Optimized solution
N,W = list(map(int,input().split()))
WV = [[0,0]] + [list(map(int,input().split())) for _ in range(N)]

sumV = sum([v for _,v in WV])
dp = [[float('inf') for _ in range(sumV+1)] for _ in range(N+1)]
dp[0][0] = 0
for i in range(1, N+1):
  tmpw, tmpv = WV[i]
  for j in range(sumV+1):
    if j-tmpv>=0:
      dp[i][j] = min(dp[i-1][j],dp[i-1][j-tmpv]+tmpw)
    else:
      dp[i][j] = dp[i-1][j]

ans = -float('inf')
for row in dp:
  for j,w in enumerate(row):
    if w<=W and ans<j:
      ans = j
print(ans)
# Original solution
n,W = list(map(int,input().split()))
w = [0]*(n+1)
v = [0]*(n+1)
for i in range(1,n+1): w[i],v[i] = list(map(int,input().split()))
mv = n*max(v)
dp = [[float("INF")]*(mv+1) for _ in range(n+1)]
for i in range(n): dp[i][0] = 0
for i in range(1,n+1):
    for s in range(1,mv+1):
        if s - v[i] < 0: dp[i][s] = dp[i-1][s]
        else: dp[i][s] = min(dp[i-1][s], dp[i-1][s-v[i]] + w[i])
ans = 0
for x in range(1,mv+1):
    if dp[n][x] <= W: ans = x
print(ans)

# Optimized solution
n,W = list(map(int,input().split()))
w = [0]*n
v = [0]*n
for i in range(n): w[i],v[i] = list(map(int,input().split()))
mv = n*max(v)
dp = [[float("INF")]*(mv+1) for _ in range(n+1)]
dp[0][0] = 0
for i in range(n):
    for s in range(mv+1):
        if s - v[i] < 0: dp[i+1][s] = dp[i][s]
        else: dp[i+1][s] = min(dp[i][s], dp[i][s-v[i]] + w[i])
ans = 0
for x in range(1,mv+1):
    if dp[n][x] <= W: ans = x
print(ans)
# Original solution
n,W = list(map(int,input().split()))
w = [0]*n
v = [0]*n
for i in range(n): w[i],v[i] = list(map(int,input().split()))
mv = n*max(v)
dp = [[float("INF")]*(mv+1) for _ in range(n+1)]
dp[0][0] = 0
for i in range(n):
    for s in range(mv+1):
        if s - v[i] < 0: dp[i+1][s] = dp[i][s]
        else: dp[i+1][s] = min(dp[i][s], dp[i][s-v[i]] + w[i])
ans = 0
for x in range(1,mv+1):
    if dp[n][x] <= W: ans = x
print(ans)

# Optimized solution
n,W = list(map(int,input().split()))
w = [0]*n
v = [0]*n
for i in range(n): w[i],v[i] = list(map(int,input().split()))
mv = sum(v)
dp = [[float("INF")]*(mv+1) for _ in range(n+1)]
dp[0][0] = 0
for i in range(n):
    for s in range(mv+1):
        if s - v[i] < 0: dp[i+1][s] = dp[i][s]
        else: dp[i+1][s] = min(dp[i][s], dp[i][s-v[i]] + w[i])
ans = 0
for x in range(1,mv+1):
    if dp[n][x] <= W: ans = x
print(ans)
# Original solution
import sys

stdin = sys.stdin

ni = lambda: int(ns())
na = lambda: list(map(int, stdin.readline().split()))
ns = lambda: stdin.readline().rstrip()  # ignore trailing spaces

n, W = na()
wv = [na() for _ in range(n)]
dp = [0]+[float("inf")]*(10**5)
for i in range(n):
      for j in range(10**5,1,-1):
        dp[j] = min(dp[j],dp[j-wv[i][1]]+wv[i][0])

res = 0
for v,e in enumerate(dp):
  if e <= W:
    res = v
    
print(res)
      

# Optimized solution
import sys

stdin = sys.stdin

ni = lambda: int(ns())
na = lambda: list(map(int, stdin.readline().split()))
ns = lambda: stdin.readline().rstrip()  # ignore trailing spaces

n, W = na()
wv = [na() for _ in range(n)]
dp = [0]+[float("inf")]*(10**5)
for i in range(n):
      for j in range(10**5,wv[i][1]-1,-1):
        dp[j] = min(dp[j],dp[j-wv[i][1]]+wv[i][0])

res = 0
for v,e in enumerate(dp):
  if e <= W:
    res = v
    
print(res)
# Original solution
import sys
# input処理を高速化する
input = sys.stdin.readline
# 入力
N, W = list(map(int, input().split()))
array = [list(map(int, input().split())) for _ in range(N)]  # [重さ、価値]
# sum_vの取りうる上限値
# MAX_V = (10**3 + 1) * N
MAX_V = 0
for line in array:
    MAX_V += line[1]
MAX_V += 1
# 最小値を求めるので無限大の値
f_inf = float('inf')


def chmin(a, b):
    if a <= b:
        return a
    else:
        return b


def knapsack(n, w):
    # dpの初期化　dp[i][sum_v]は重さの総和の最小値
    dp = [[f_inf] * MAX_V for j in range(N + 1)]
    # 初期条件
    dp[0][0] = 0
    # forは全て関数の中で回す。
    # 入力
    for i in range(N):
        # w, v = map(int, input().split())
        for sum_v in range(MAX_V):
            # i番目の品物を選ぶ場合
            if sum_v - array[i][1] >= 0:
                dp[i + 1][sum_v] = chmin(dp[i + 1][sum_v],
                                         dp[i][sum_v - array[i][1]] + array[i][0])
            # i番目の品物を選ばない場合
            dp[i + 1][sum_v] = chmin(dp[i + 1][sum_v], dp[i][sum_v])
    # dp[N][sum_v]の値が、W以下であるsum_vの値の最大値
    ans = 0
    for sum_v in range(MAX_V):
        if dp[N][sum_v] <= W:
            ans = sum_v
    print(ans)


knapsack(N, W)


# Optimized solution
# N個、重さW
N, W = list(map(int, input().split()))

# 重さ, 価値
array = [list(map(int, input().split())) for _ in range(N)]

# 価値の最大値
sum = 1
for i in range(N):
    sum += array[i][1]

weights = [[float('inf')] * (sum + 1) for _ in range(N + 1)]
# 初期値
weights[0][0] = 0
# 価値ごとの重さの最小値を出す
for n in range(N):
    # 価値が0..1000までのそれぞれについて、価値を超えているうちの重さの最小値を算出する
    for v in range(sum + 1):
        # n回目の品物を持ち帰らない場合の重量
        weights[n + 1][v] = weights[n][v]
        weight = weights[n][v - array[n][1]] + array[n][0]
        if weight < weights[n + 1][v]:
            weights[n + 1][v] = weight

ans = 0
for i in range(sum):
    if weights[N][i] <= W:
        ans = i
print(f"{ans}")
# Original solution
import sys
input = sys.stdin.readline

N, W = list(map(int, input().split()))

INF = float("inf")
dp = [0] + [INF] * 10**5

for _ in range(N):
  w, v = list(map(int, input().split()))
  for j in range(10**5, v-1, -1):
    dp[j] = min(dp[j], dp[j-v] + w)

for i, x in enumerate(dp):
  if x <= W:
    ans = i

print(ans)

# Optimized solution
N, W = list(map(int, input().split()))

INF = float("inf")
dp = [0] + [INF] * 10**5

for _ in range(N):
  w, v = list(map(int, input().split()))
  for j in range(10**5, v-1, -1):
    dp[j] = min(dp[j], dp[j-v] + w)

for i, x in enumerate(dp):
  if x <= W:
    ans = i

print(ans)
# Original solution
def main2():
    #1:初期化
    N,W = list(map(int,input().split()))
    wv = []
    for _ in range(N):
        wv.append(list(map(int,input().split())))
    dp = [[W+1]*(1000*N+1) for i in range(N+1)] #valueの最大値は10**3なので全てが10**3でも入るような配列を用意．
    #print(*dp,sep="\n")

    #2:初期値(dp[0][0]だけだと結果が合わない)
    for i in range(N+1):
        dp[i][0] = 0

    #3:dp実行部(貰うDP)
    for i in range(1,N+1):
        for j in range(1,1000*N+1):
            if wv[i-1][1] <= j: #dpの横が重さだが，jが重さ以下ならそもそも入れられない．
                dp[i][j] = min(dp[i-1][j], dp[i-1][j-wv[i-1][1]]+wv[i-1][0])
            else:
                dp[i][j] = dp[i-1][j]
            #print(i,j)
            #print(*dp,sep="\n")

    #4:出力
    #print(*dp,sep="\n")
    output = 0
    for i in range(1000*N+1):
        if dp[N][i] <= W:
            output = i
    print(output)

if __name__ == '__main__':
    main2()

# Optimized solution
def main():
    #1:初期化
    N,W = list(map(int,input().split()))
    dp = [W+1]*(N*10**3+1)

    #2:初期値
    dp[0] = 0

    #3:dp実行部(貰うDP)
    for i in range(N):
        w, v = list(map(int,input().split()))
        for i in range(N*10**3, v-1, -1):
            tmp = dp[i-v] + w
            if dp[i] > tmp:
                dp[i] = tmp
        #print(dp,sep="\n")

    #4:出力
    output = 0
    for i in range(N*10**3+1):
        if dp[i] <= W:
            output = i
    print(output)

if __name__ == '__main__':
    main()
# Original solution
N,W = list(map(int,input().split()))
w,v = [0]*N,[0]*N
for i in range(N):
    w[i],v[i] = list(map(int,input().split()))
    
dp = [[10**9+1]*(sum(v)+1) for i in range(N+1)]
dp[0][0] = 0

#v[i]を使うかどうか
for i in range(N):
    #価値がjのときの最小の重さ総量
    for j in range(sum(v)+1):
        if j >= v[i]:
            dp[i+1][j] = min(dp[i][j-v[i]]+w[i],dp[i][j])
        else:
            dp[i+1][j] = dp[i][j]
            
ans = 0

for i in range(sum(v)+1):
    if dp[N][i] <= W:
        ans = max(ans,i)
print(ans)

# Optimized solution
N,W = list(map(int,input().split()))
w,v = [0]*N,[0]*N
for i in range(N):
    w[i],v[i] = list(map(int,input().split()))
    
# dp[i][j]:i番目の品物を詰めて価値jのときの重さの最小値
dp = [[10**9+1]*(sum(v)+1) for i in range(N+1)]
dp[0][0] = 0

#v[i-1]を使うかどうか
for i in range(1,N+1):
    #価値がjのときの最小の重さ
    for j in range(sum(v)+1):
        if j >= v[i-1]:
            dp[i][j] = min(dp[i-1][j-v[i-1]]+w[i-1],dp[i-1][j])
        else:
            dp[i][j] = dp[i-1][j]

# 重さがW以下のもので価値が最大となるものを探す
ans = 0
for i in range(sum(v)+1):
    if dp[-1][i] <= W:
        ans = max(ans,i)
print(ans)