#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 110;
int castal[N][N];
bool dp[N * N];
int st[N], sum[N];
int n;
int ifsatisfi(int x, int num) // 检测第x组城堡是否能满足当前高度
{
memset(dp, false, sizeof(dp));
dp[0] = true;
for (int i = 1; i <= st[x]; i++)
{
for (int j = num; j >= castal[x][i]; j--)
{
if (dp[j - castal[x][i]] == true) dp[j] = true;
}
}
if (sum[x] > num && dp[num] == false) return -2; // 如果城堡总高度大于当前所求的高度且当前高度不能被凑出,依然可以找到更大的高度
else if (sum[x] <= num && dp[num] == false) return -1; // 如果城堡总高度小于等于当前所求高度,且当前高度不能被凑出,则需要找到小一点的高度
else if (dp[num] == true) return 1; // 满足,找更大高度
}
bool judge(int mid)
{
int state = 2;
for (int i = 1; i <= n; i++)
{
int temp = ifsatisfi(i, mid);
if (temp == -1) // 只要有一个城堡的高度小于当前所求的高度都需要降低要求
{
state = 1;
break;
}
}
if (state == 1) return false;
else return true;
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
int a;
cin >> a;
int tar = 0;
while (a != -1)
{
castal[i][++tar] = a;
sum[i] += a;
st[i] = tar;
cin >> a;
}
}
//for (int i = 1; i <= n; i++) cout << st[i] << endl;
if (n == 1)
{
cout << sum[n] << endl;
return 0;
}
int left = 1, right = 10000;
while (left < right) // 二分合适的高度
{
int mid = (left + right + 1) / 2;
if (judge(mid)) left = mid; //如果当前高度可以被满足,则还可以更高
else right = mid - 1;
}
cout << left << endl;
return 0;
}