IOI 1994 - The Triangle
Problem Statement Given a triangle of n rows of positive integers, find a path from the top to the bottom such that the sum of the numbers along the path is maximized. At each step, you may move to the element directl...
Source-first archive entry
This page is built from the copied files in competitive_programming/ioi/1994/triangle. Edit
competitive_programming/ioi/1994/triangle/solution.tex to update the written solution and
competitive_programming/ioi/1994/triangle/solution.cpp to update the implementation.
The website does not replace those files with hand-maintained HTML. It reads the copied source tree during the build and exposes the exact files below.
Problem Statement
Rendered from the "Problem Statement" section inside solution.tex because this entry has no separate statement file.
Given a triangle of $n$ rows of positive integers, find a path from the top to the bottom such that the sum of the numbers along the path is maximized. At each step, you may move to the element directly below or to the element directly below and one position to the right.
Example:
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
The maximum sum path is $7 \to 3 \to 8 \to 7 \to 5 = 30$.
Constraints: $1 \le n \le 100$, each element is between 0 and 99.
Editorial
Rendered from the copied solution.tex file. The original TeX source remains
available below.
Solution Approach
This is a classic dynamic programming problem. We define: \[ \text{dp}[i][j] = \text{maximum sum achievable from element } (i,j) \text{ down to the bottom row} \]
Base Case
For the bottom row $i = n-1$: \[ \text{dp}[n-1][j] = \text{val}[n-1][j] \]
Recurrence
For rows $i = n-2$ down to $0$: \[ \text{dp}[i][j] = \text{val}[i][j] + \max\!\big(\text{dp}[i+1][j],\;\text{dp}[i+1][j+1]\big) \]
Answer
The answer is $\text{dp}[0][0]$.
Why Bottom-Up?
Bottom-up DP avoids recursion overhead and is straightforward: we start from the last row and propagate maxima upward. The triangle can be modified in place, requiring no extra memory beyond the input array.
C++ Solution
#include <cstdio>
#include <algorithm>
using namespace std;
int tri[101][101];
int main() {
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
for (int j = 0; j <= i; j++)
scanf("%d", &tri[i][j]);
// Bottom-up DP: modify triangle in place
for (int i = n - 2; i >= 0; i--)
for (int j = 0; j <= i; j++)
tri[i][j] += max(tri[i + 1][j], tri[i + 1][j + 1]);
printf("%d\n", tri[0][0]);
return 0;
}
Complexity Analysis
Time complexity: $O(n^2)$. We visit each element of the triangle exactly once. The total number of elements is $\frac{n(n+1)}{2}$, so the work is $\Theta(n^2)$.
Space complexity: $O(n^2)$ for storing the triangle. Since we modify the triangle in place, no additional space is needed beyond the input. Alternatively, one could use a 1D array of size $n$ for a rolling approach, yielding $O(n)$ extra space.
Code
Exact copied C++ implementation from solution.cpp.
// IOI 1994 - The Triangle
// Bottom-up DP: find max-sum path from top to bottom
// Time: O(n^2), Space: O(n^2)
#include <bits/stdc++.h>
using namespace std;
int tri[101][101];
int main() {
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
for (int j = 0; j <= i; j++)
scanf("%d", &tri[i][j]);
// Bottom-up DP: modify triangle in place
for (int i = n - 2; i >= 0; i--)
for (int j = 0; j <= i; j++)
tri[i][j] += max(tri[i + 1][j], tri[i + 1][j + 1]);
printf("%d\n", tri[0][0]);
return 0;
}
Source Files
Exact copied source-of-truth files. Edit solution.tex for the write-up and solution.cpp for the implementation.
\documentclass[11pt,a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage{amsmath,amssymb}
\usepackage{geometry}
\geometry{margin=2.5cm}
\usepackage{listings}
\usepackage{xcolor}
\usepackage{hyperref}
\lstset{
language=C++,
basicstyle=\ttfamily\small,
keywordstyle=\color{blue}\bfseries,
commentstyle=\color{green!60!black},
stringstyle=\color{red!70!black},
numbers=left,
numberstyle=\tiny\color{gray},
numbersep=8pt,
frame=single,
breaklines=true,
tabsize=4,
showstringspaces=false
}
\title{IOI 1994 -- The Triangle}
\author{Solution}
\date{}
\begin{document}
\maketitle
\section{Problem Statement}
Given a triangle of $n$ rows of positive integers, find a path from the top to the bottom
such that the sum of the numbers along the path is maximized.
At each step, you may move to the element directly below or to the element
directly below and one position to the right.
\medskip
\noindent\textbf{Example:}
\begin{verbatim}
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
\end{verbatim}
The maximum sum path is $7 \to 3 \to 8 \to 7 \to 5 = 30$.
\medskip
\noindent\textbf{Constraints:} $1 \le n \le 100$, each element is between 0 and 99.
\section{Solution Approach}
This is a classic dynamic programming problem. We define:
\[
\text{dp}[i][j] = \text{maximum sum achievable from element } (i,j) \text{ down to the bottom row}
\]
\subsection{Base Case}
For the bottom row $i = n-1$:
\[
\text{dp}[n-1][j] = \text{val}[n-1][j]
\]
\subsection{Recurrence}
For rows $i = n-2$ down to $0$:
\[
\text{dp}[i][j] = \text{val}[i][j] + \max\!\big(\text{dp}[i+1][j],\;\text{dp}[i+1][j+1]\big)
\]
\subsection{Answer}
The answer is $\text{dp}[0][0]$.
\subsection{Why Bottom-Up?}
Bottom-up DP avoids recursion overhead and is straightforward: we start from the last
row and propagate maxima upward. The triangle can be modified in place, requiring no
extra memory beyond the input array.
\section{C++ Solution}
\begin{lstlisting}
#include <cstdio>
#include <algorithm>
using namespace std;
int tri[101][101];
int main() {
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
for (int j = 0; j <= i; j++)
scanf("%d", &tri[i][j]);
// Bottom-up DP: modify triangle in place
for (int i = n - 2; i >= 0; i--)
for (int j = 0; j <= i; j++)
tri[i][j] += max(tri[i + 1][j], tri[i + 1][j + 1]);
printf("%d\n", tri[0][0]);
return 0;
}
\end{lstlisting}
\section{Complexity Analysis}
\begin{itemize}
\item \textbf{Time complexity:} $O(n^2)$. We visit each element of the triangle exactly once.
The total number of elements is $\frac{n(n+1)}{2}$, so the work is $\Theta(n^2)$.
\item \textbf{Space complexity:} $O(n^2)$ for storing the triangle. Since we modify the
triangle in place, no additional space is needed beyond the input.
Alternatively, one could use a 1D array of size $n$ for a rolling approach,
yielding $O(n)$ extra space.
\end{itemize}
\end{document}
// IOI 1994 - The Triangle
// Bottom-up DP: find max-sum path from top to bottom
// Time: O(n^2), Space: O(n^2)
#include <bits/stdc++.h>
using namespace std;
int tri[101][101];
int main() {
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
for (int j = 0; j <= i; j++)
scanf("%d", &tri[i][j]);
// Bottom-up DP: modify triangle in place
for (int i = n - 2; i >= 0; i--)
for (int j = 0; j <= i; j++)
tri[i][j] += max(tri[i + 1][j], tri[i + 1][j + 1]);
printf("%d\n", tri[0][0]);
return 0;
}