#include<bits/stdc++.h>
using namespace std;
#define int long long
#define printv(v) for(int i=0;i<v.size();i++)cout<<v[i]<<" ";cout<<"\n";
#define printv2(v) for(int i=1;i<v.size();i++)cout<<v[i]<<" ";cout<<"\n";
#define prints(s) set<int>::iterator it;for(it=s.begin();it!=s.end();it++)cout<<*it<<" ";cout<<"\n";
#define inv(v,n) vector<int>v(n);for(int i=0;i<n;i++)cin>>v[i];
#define inv2(v,n) vector<int>v(n+1);for(int i=1;i<=n;i++)cin>>v[i];  
#define ins(s,n) set<int>s;for(int i=0;i<n;i++){int c;cin>>c;s.insert(c);}
#define sort1(v) sort(v.begin(),v.end());
#define reverse1(v) reverse(v.begin(),v.end());
#define sort2(v) sort(v.begin()+1,v.end());
#define reverse2(v) reverse(v.begin()+1,v.end());
#define loop(i,a,b) for(int i=a;i<=b;i++)


//_________________________________________________________________________________________________________________________________________________//
int vis[1000000];
void dfs(vector<int>g[],int v)
{
	vis[v]=1;
	cout<<v<<" ";
	for(int i=0;i<g[v].size();i++)
	{
		if(vis[g[v][i]]==0)
		{
			dfs(g,g[v][i]);
		}
	}
}
//int e,v;
//	cin>>e>>v;
//	vector<int>g[v+1];
//	for(int i=0;i<e;i++)
//	{
//		int a,b;
//		cin>>a>>b;
//		g[a].push_back(b);
//	//	g[b].push_back(a);
//	}
//_____________________________________________________________________________________________________________________________________________________//
/*int segt[2000000+10];
int lazy[2000000+10];
void build(int v[],int node,int s,int e)
{
	if(s==e)
	{
		segt[node]=v[s];
	}
	else
	{
		int m=(s+e)/2;
		build(v,2*node,s,m);
		build(v,2*node+1,m+1,e);
		segt[node]=segt[2*node]+segt[2*node+1];
	}
}
void update(int node,int s,int e,int idx,int val)
{
	if(s==e)
	{
		segt[node]=val;
	}
	else
	{
		int m=(s+e)/2;
		if(s<=idx&&idx<=m)
        {
            update(2*node,s,m,idx,val);
        }
        else
        {
            update(2*node+1,m+1,e,idx,val);
        }
        segt[node]=segt[2*node]+segt[2*node+1];
	}
}
int query(int node,int s,int e,int l,int r)
{
    if(r<s||e<l)
    {
        return 0;
    }
    if(l<=s&&e<=r)
    {
        return segt[node];
    }
    int m=(s+e)/2;
    int p1=query(2*node,s,m,l,r);
    int p2=query(2*node+1,m+1,e,l,r);
    return (p1+p2);
}
void updaterange(int node, int start, int end, int l, int r, int val)
{
    if(lazy[node] != 0)
    { 
        segt[node] += (end - start + 1) * lazy[node];    // Update it
        if(start != end)
        {
            lazy[node*2] += lazy[node];                  // Mark child as lazy
            lazy[node*2+1] += lazy[node];                // Mark child as lazy
        }
        lazy[node] = 0;                                  // Reset it
    }
    if(start > end or start > r or end < l)              // Current segment is not within range [l, r]
        return;
    if(start >= l and end <= r)
    {
        // Segment is fully within range
        segt[node] += (end - start + 1) * val;
        if(start != end)
        {
            // Not leaf node
            lazy[node*2] += val;
            lazy[node*2+1] += val;
        }
        return;
    }
    int mid = (start + end) / 2;
    updaterange(node*2, start, mid, l, r, val);        // Updating left child
    updaterange(node*2 + 1, mid + 1, end, l, r, val);   // Updating right child
    segt[node] = segt[node*2] + segt[node*2+1];        // Updating root with max value 
}

int queryrange(int node, int start, int end, int l, int r)
{
    if(start > end or start > r or end < l)
        return 0;         // Out of range
    if(lazy[node] != 0)
    {
        // This node needs to be updated
        segt[node] += (end - start + 1) * lazy[node];            // Update it
        if(start != end)
        {
            lazy[node*2] += lazy[node];         // Mark child as lazy
            lazy[node*2+1] += lazy[node];    // Mark child as lazy
        }
        lazy[node] = 0;                 // Reset it
    }
    if(start >= l and end <= r)             // Current segment is totally within range [l, r]
        return segt[node];
    int mid = (start + end) / 2;
    int p1 = queryrange(node*2, start, mid, l, r);         // Query left child
    int p2 = queryrange(node*2 + 1, mid + 1, end, l, r); // Query right child
    return (p1 + p2);
}
*/
//void build(int v[],int node,int s,int e)//put node=1;s=1;e=1 for 1 indexed and node=1;s=0;e=n-1 for 0 indexed//always provide array here instead of vector.
//void update(int node,int s,int e,int idx,int val)//put node=1;s=1;e=1;idx=index;val=value for 1 indexed and node=1;s=0;e=0;idx=index;val=value for 0 indexed
//int query(int node,int s,int e,int l,int r)// put node=1;s=1;e=n ans l and r for 1 indexed put node=1;s=0;e=n-1 ans l and r for 1 indexed


//______________________________________________________________________________________________________________________________________________________//
int ispalin(string s){for(int i=0;i<s.size()/2;i++){if(s[i]!=s[s.size()-1-i]){	return 0;}}return 1;}
//______________________________________________________________________________________________________________________________________________________//
void computeLPSArray(string pat, int M,int* lps) { int len = 0; lps[0] = 0; int i = 1; while (i < M) { if (pat[i] == pat[len]) { len++; lps[i] = len; i++; } else { if (len != 0) { len = lps[len - 1]; } else { lps[i] = 0; i++; } } } }
void kmp(string pat, string txt,vector<int>&v) { int M = pat.size(); int N = txt.size(); int lps[M]; computeLPSArray(pat, M, lps); int i = 0; int j = 0; while (i < N) { if (pat[j] == txt[i]) { j++; 	i++; } if (j == M) { 	v.push_back(i-j);	j = lps[j - 1]; } else if (i < N && pat[j] != txt[i]) { 	if (j != 0) j = lps[j - 1]; else i = i + 1; } } }
//kmp(pattern to be searched,main pattern,vector)
//all answers will be zero indexed.
//pass an empty vector v it will store all starting indexes.
//______________________________________________________________________________________________________________________________________________________//
const int MAXS = 500; 
const int MAXC = 26; 
int out[MAXS]; 
int f[MAXS]; 
int g[MAXS][MAXC]; 
int buildMatchingMachine(vector<string>arr, int k) { memset(out, 0, sizeof out); memset(g, -1, sizeof g); int states = 1; for (int i = 0; i < k; ++i) { const string &word = arr[i]; int currentState = 0; for (int j = 0; j < word.size(); ++j) { int ch = word[j] - 'a'; if (g[currentState][ch] == -1) g[currentState][ch] = states++; currentState = g[currentState][ch]; } out[currentState] |= (1 << i); } for (int ch = 0; ch < MAXC; ++ch) if (g[0][ch] == -1) g[0][ch] = 0; memset(f, -1, sizeof f); queue<int> q; for (int ch = 0; ch < MAXC; ++ch) { if (g[0][ch] != 0) { f[g[0][ch]] = 0; q.push(g[0][ch]); } } while (q.size()) { int state = q.front(); q.pop(); for (int ch = 0; ch <= MAXC; ++ch) { if (g[state][ch] != -1) { int failure = f[state]; while (g[failure][ch] == -1) failure = f[failure]; failure = g[failure][ch]; f[g[state][ch]] = failure; out[g[state][ch]] |= out[failure]; 	q.push(g[state][ch]); } } } return states; } 
int findNextState(int currentState, char nextInput) { int answer = currentState; int ch = nextInput - 'a'; while (g[answer][ch] == -1) answer = f[answer]; return g[answer][ch]; } 
void aho(vector<string>arr, string text,vector<vector<pair<int,int> > >&v) { int k=arr.size();buildMatchingMachine(arr, k); int currentState = 0; 	for (int i = 0; i < text.size(); ++i) { currentState = findNextState(currentState, text[i]); if (out[currentState] == 0) 	continue; for (int j = 0; j < k; ++j) { if (out[currentState] & (1 << j)) { pair<int,int>pr;pr.first=i - arr[j].size() + 1;pr.second=i;v[j].push_back(pr);} } } } 
//aho(vector of string whose patterns are to be searched,main text,vector<vector<pair<int,int> > > of size of arr)
//all answers will be 0 indexed
//only used for alphabets
//__________________________________________________________________________________________________________________________________________________________________//
void simpleSieve(int limit, vector<int>& prime) {  bool mark[limit + 1];  memset(mark, false, sizeof(mark));  for (int i = 2; i <= limit; ++i) {   if (mark[i] == false) {   prime.push_back(i); for (int j = i; j <= limit; j += i) mark[j] = true; } } } 
void primes(int low, int high,vector<int>&x,map<int,int>&mp) { int limit = floor(sqrt(high)) + 1; vector<int> prime; simpleSieve(limit, prime); int n = high - low + 1;  bool mark[n + 1];  memset(mark, false, sizeof(mark));  for (int i = 0; i < prime.size(); i++) {  int loLim = floor(low / prime[i]) * prime[i]; if (loLim < low) loLim += prime[i]; if(loLim==prime[i])   loLim += prime[i]; for (int j = loLim; j <= high; j += prime[i]) mark[j - low] = true; } for (int i = low; i <= high; i++) if (!mark[i - low]) {x.push_back(i);mp[i]=1;}mp[1]=0;} 
//primes(low,high,v,m) v will return all primes in range [low,high] and m will tell if it is prime in that range.
//____________________________________________________________________________________________________________________________________________________________//
#define MAXN 1000001 //set it till where we want prime factorization.
int spf[MAXN];  
void sieve() { spf[1] = 1; for (int i=2; i<MAXN; i++) spf[i] = i; for (int i=4; i<MAXN; i+=2) spf[i] = 2; for (int i=3; i*i<MAXN; i++) { if (spf[i] == i) { 	for (int j=i*i; j<MAXN; j+=i) if (spf[j]==j) spf[j] = i; } } } 
void primefact(int x,vector<int>&v,map<int,int>&mp) {  sieve();while (x != 1) { if(mp[spf[x]]==0)		v.push_back(spf[x]); 	mp[spf[x]]++;x = x / spf[x]; }  }
//primefact(x,v,m)
//___________________________________________________________________________________________________________________________________________________________//
int power(int x, int y, int p){int res = 1;x = x % p;while (y > 0){if (y & 1)res=(res*x) % p;y = y>>1;x = (x*x) % p;}return res;}
//________________________________________________________________________________________________________________________________________________________________//
const int N = 1000001;//set it till where we want factorial of 
  int factorialNumInverse[N + 1]; int naturalNumInverse[N + 1]; int fact[N + 1]; void InverseofNumber(int p) {  naturalNumInverse[0] = naturalNumInverse[1] = 1;  for (int i = 2; i <= N; i++)   naturalNumInverse[i] = naturalNumInverse[p % i] * (p - p / i) % p; } void InverseofFactorial(int p) {  factorialNumInverse[0] = factorialNumInverse[1] = 1; for (int i = 2; i <= N; i++) factorialNumInverse[i] = (naturalNumInverse[i] * factorialNumInverse[i - 1]) % p; } void factorial(int p) {  fact[0] = 1;  for (int i = 1; i <= N; i++) {  fact[i] = (fact[i - 1] * i) % p; } } int ncr(int N, int R, int p) {  InverseofNumber(p);InverseofFactorial(p);factorial(p);  int ans = ((fact[N] * factorialNumInverse[R])   % p * factorialNumInverse[N - R])  % p; return ans; }  
//ncr(n,r,p)
//________________________________________________________________________________________________________________________________________________________//
/////////////////////////////////////HELPING FUNCTIONS///////////////////////////////////////////////////

int sum(vector<int>v,int a,int b){int ans=0;for(int i=a;i<=b;i++)ans=ans+v[i];return ans;}
int sum(int arr[],int a,int b){int ans=0;for(int i=a;i<=b;i++)ans=ans+arr[i];return ans;}
void count(vector<int>v,int a,int b,vector<int>&x,map<int,int>&m){for(int i=a;i<=b;i++){if(m[v[i]]==0){x.push_back(v[i]);}m[v[i]]++;}}




int dp[100000+1][4];


main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);//ncr(n,r,p)
	int n;
	cin>>n;
	vector<int>a(n+1),b(n+1),c(n+1);
	for(int i=1;i<=n;i++)
	cin>>a[i]>>b[i]>>c[i];
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=3;j++)
		{
			if(i==1)
			{
				if(j==1)dp[i][j]=a[i];
				else if(j==2)dp[i][j]=b[i];
				else dp[i][j]=c[i];
			}
			else
			{
				if(j==1)
				{
					dp[i][2]=max(dp[i][2],dp[i-1][1]+b[i]);
					dp[i][3]=max(dp[i][3],dp[i-1][1]+c[i]);
				}
				else if(j==2)
				{
					dp[i][1]=max(dp[i][1],dp[i-1][2]+a[i]);
					dp[i][3]=max(dp[i][3],dp[i-1][2]+c[i]);
				}
				else
				{
					dp[i][1]=max(dp[i][1],dp[i-1][3]+a[i]);
					dp[i][2]=max(dp[i][2],dp[i-1][3]+b[i]);
				}
			}
		}
	}
	cout<<max(dp[n][1],max(dp[n][2],dp[n][3]));
}

Measured memory_bytes: 6656