/*
* Problem :: 2096 / 내려가기
*
* Kind :: Dynamic Programming
*
* Insight
* - 메모리 제한이 4MB 밖에 안되네...?
* 딱 봐도 DP 로 풀어야 하는데
* A[N][3], dpMax[N][3], dpMin[N][3] 을 하면 100% 메모리 초과다
* + 사실, 숫자표에서 현재 줄 i 의 dpMax 또는 dpMin 을 구하려고 할 때
* dpMax[i][0,1,2] 와 dpMin[i][0,1,2] 는
* 현재 숫자표에 쓰여있는 수 A[i][0,1,2] 와
* dpMax[i-1][0,1,2] 그리고 dpMin[i-1][0,1,2] 만 알면 구할 수 있다
* # 점화식은 다음과 같다
* dpMax[i][0] = A[i][0] + max(dpMax[i-1][0], dpMax[i-1][1])
* dpMax[i][1] = A[i][1] + max({dpMax[i-1][0], dpMax[i-1][1], dpMax[i-1][2]})
* dpMax[i][2] = A[i][2] + max(dpMax[i-1][1], dpMax[i-1][2])
*
* dpMin[i][0] = A[i][0] + min(dpMin[0], dpMin[1])
* dpMin[i][1] = A[i][1] + min({dpMin[0], dpMin[1], dpMin[2]})
* dpMin[i][2] = A[i][2] + min(dpMin[i-1][1], dpMin[i-1][2])
* -> 현재 줄에 쓰인 점수 A[3], 이전 줄까지 갱신된 dpMax[3], dpMin[3] 만으로
* 위의 점화식을 계산할 수 있다
* 즉, 위의 식에 필요한 정보 외에는 저장을 해둘 필요가 없다
* 따라서 공간복잡도를 다음처럼 줄일 수 있다
* A[N][3] => A[3]
* dpMax[N][3] => dpMax[3]
* dpMin[N][3] => dpMin[3]
*
* Point
* - 그렇다고 위의 점화식을
* dpMax[0] = A[0] + max(dpMax[0], dpMax[1])
* 처럼 계산하면 안된다
* + 어디까지나 dp 를 갱신할 때는 이전 줄까지의 dp 를 이용해야 한다
* dpMax[0] 을 위처럼 갱신후
* dpMax[1] = A[1] + max({dpMax[0], dpMax[1], dpMax[2]}) 을 계산하면
* dpMax[1] 과 dpMax[2] 는 이전 줄 기준 dp 지만
* dpMax[0] 은 현재 줄 기준 dp 이기 때문에 논리적으로 모순이 발생한다
* # 중간에 tmpMax, tmpMin 배열을 선언해서
* 현재 줄을 기준으로 dp 를 갱신한 값을 임시로 넣은 후
* 다시 이를 dpMax, dpMin 에 복사하는 방식으로 dp 를 갱신해주자
*/
//
// BOJ
// ver.C++
//
// Created by GGlifer
//
// Open Source
#include <iostream>
#include <cstring>
using namespace std;
#define endl '\n'
// Set up : Global Variables
/* None */
// Set up : Functions Declaration
/* None */
int main()
{
// Set up : I/O
ios::sync_with_stdio(false);
cin.tie(nullptr);
// Set up : Input
int N; cin >> N;
int dpMax[3], dpMin[3];
/* 숫자표의 첫줄 초기화 */
for (int i=0; i<3; i++) {
int n; cin >> n;
dpMax[i] = dpMin[i] = n;
}
for (int i=1; i<N; i++) {
int A[3]; /* 숫자표의 현재 줄에 쓰여있는 점수 */
for (int j=0; j<3; j++)
cin >> A[j];
// Process
int tmpMax[3], tmpMin[3];
/* tmpMax 계산 */
tmpMax[0] = A[0] + max(dpMax[0], dpMax[1]);
tmpMax[1] = A[1] + max({dpMax[0], dpMax[1], dpMax[2]});
tmpMax[2] = A[2] + max(dpMax[1], dpMax[2]);
/* tmpMin 계산 */
tmpMin[0] = A[0] + min(dpMin[0], dpMin[1]);
tmpMin[1] = A[1] + min({dpMin[0], dpMin[1], dpMin[2]});
tmpMin[2] = A[2] + min(dpMin[1], dpMin[2]);
/* dpMax, dpMin 갱신 */
memcpy(dpMax, tmpMax, sizeof(tmpMax));
memcpy(dpMin, tmpMin, sizeof(tmpMin));
}
// Control : Output
cout << max({dpMax[0], dpMax[1], dpMax[2]});
cout << ' ';
cout << min({dpMin[0], dpMin[1], dpMin[2]});
}
// Helper Functions
/* None */