#include <iostream>
#include <cstring>
#define INF 0x3f3f3f
using namespace std;
//目標:尋找揹包容量與價值。
//已知:智商+幽默感(看似都是屬性,咋整?) 但是0-1揹包的特徵很明顯,對每頭牛,取or不取,那每頭牛肯定是一個價值量
//兩個屬性,一個做容量,另一個做價值。 最後加判斷求和。
//https://blog.csdn.net/Tc_To_Top/article/details/49871783
const int mid = 100000;
const int N = 110;
int ts[N];
int tf[N];
int dp[mid*2+10];
int n;
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d %d",&ts[i],&tf[i]);
}
memset(dp,-INF,sizeof(dp));//因爲有負數,所以初始化爲一個很小的負數
dp[mid]=0;//起點爲0
for(int i=0;i<n;i++){
if(ts[i]>0){
for(int j=mid*2-1;j>=ts[i];j--){//j>=ts[i]的意思是能放的下開ts[i]
//直接從mid*2-1開始遍歷,怎麼就說明挪了100000個位置呢?
// 聯想一下最普通的0-1揹包,那個是從容器最大值開始遍歷,這個的最大值變成什麼呢?變成200000(i是dp下標,表示的是容量,即ts的和,範圍是-100000~100000)
dp[j]=max(dp[j],dp[j-ts[i]]+tf[i]);
}
}else{//ts[i]<0時正序遍歷,因爲j-ts[i]此時大於0了,從表格上來看,就是上面行的更新需要下面行的原始數據,所以正着遍歷,後面的行還是原始數據沒有變。
//https://blog.csdn.net/dr5459/article/details/9220563
//體積總和也是有上下限的,可以在上面輸入的時候就求出來。
//一個0-1揹包,一個完全揹包???????????????????????????????????????????????????
//https://www.2cto.com/kf/201508/427415.html 對稱的,正負在座標軸上關於原點對稱?
//int j = S[i]; j - S[i] < mid*2; ++j 爲啥呢? j減去ts[i],剩下的範圍小於總的,也就是ts[i]沒把全部範圍用掉?
//好像不是這麼理解,
//其實用範圍這一說可以理解,上面ts[i]爲正時,是所有可能影響的都要包括,而這裏可能影響的範圍變了,因爲ts[i]是負的,下面的減減相遇是加,上面範圍自然就更小,是爲s[i]空出來的。
for(int j=0;j<=mid*2+ts[i];j++){//爲什麼要+ts[i]???????????????????????????????????????????????????
//注意dp範圍,所有可能影響的都要包括(https://www.cnblogs.com/kuangbin/archive/2012/09/14/2684929.html)
//可能受ts[i]影響的,
dp[j]=max(dp[j],dp[j-ts[i]]+tf[i]);
}
}
}
int ans=0;
for(int i=mid;i<mid*2;i++){//從mid開始 ,因爲mid之前是負數,不考慮。
if(dp[i]>=0){//必須有這個判斷,爲什麼?因爲有的dp還是初始化的-inf
ans = max(ans,dp[i]+i-mid);//i-mid就是ts的原始值
}
}
printf("%d",ans);
return 0;
}