Problem:
Daruma Otoshi

You are playing a variant of a game called "Daruma Otoshi (Dharma Block Striking)".

At the start of a game, several wooden blocks of the same size but with varying weights
are stacked on top of each other, forming a tower.
Another block symbolizing Dharma is placed atop.
You have a wooden hammer with its head thicker than the height of a block,
but not twice that.

You can choose any two adjacent blocks, except Dharma on the top,
differing at most 1 in their weight,
and push both of them out of the stack with a single blow of your hammer.
The blocks above the removed ones then fall straight down,
without collapsing the tower.

You cannot hit a block pair with weight difference of 2 or more,
for that makes too hard to push out blocks while keeping the balance of the tower.
There is no chance in hitting three blocks out at a time,
for that would require superhuman accuracy.

The goal of the game is to remove as many blocks as you can.
Your task is to decide the number of blocks that can be removed
by repeating the blows in an optimal order.

Figure D1. Striking out two blocks at a time

In the above figure, with a stack of four blocks weighing 1, 2, 3, and
1, in this order from the bottom, you can hit middle
two blocks, weighing 2 and 3, out from the stack. The blocks above will
then fall down, and two blocks weighing 1 and the Dharma block will remain.
You can then push out the remaining pair of weight-1 blocks after that.

Input

The input consists of multiple datasets.
The number of datasets is at most 50.
Each dataset is in the following format.

n

w1 w2 … wn

n is the number of blocks, except Dharma on the top.
n is a positive integer not exceeding 300.
wi gives the weight of the i-th block counted from the bottom.
wi is an integer between 1 and 1000, inclusive.

The end of the input is indicated by a line containing a zero.

Output

For each dataset, output in a line the maximum number of blocks you can remove.

Sample Input

4
1 2 3 4
4
1 2 3 1
5
5 1 2 3 6
14
8 7 1 4 3 5 4 1 6 8 10 4 6 5
5
1 3 5 1 3
0

Output for the Sample Input

4
4
2
12
0

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using static System.Math;
using static System.Array;
using static AtCoder.Tool;
namespace AtCoder
{
    class AC
    {
        const int MOD = 1000000007;
        const int INF = int.MaxValue / 2;
        const long SINF = long.MaxValue / 2;
        const double EPS = 1e-8;
        static readonly int[] dI = { 0, 1, 0, -1 };
        static readonly int[] dJ = { 1, 0, -1, 0 };
        //static List<List<int>> G = new List<List<int>>();
        //static List<List<Edge>>G = new List<List<Edge>>();
        //static List<Edge> E = new List<Edge>();
        static void Main(string[] args)
        {
            //var sw = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
            //Console.SetOut(sw);
            var cin = new Scanner();
            while (true)
            {
                int n = int.Parse(Console.ReadLine());
                if (n == 0) { return; }
                var w = cin.ReadSplitInt();
                var dp = new long[n, n];
                for (var i = 0; i < n; i++) dp[i, i] = 0;
                for(var i = 0; i < n - 1; i++)
                {
                    dp[i, i + 1] = Abs(w[i + 1] - w[i]) <= 1 ? 2 : 0;
                }
                for (var L = 2; L < n; L++)
                {
                    for(var i = 0; i + L < n; i++)
                    {
                        if (dp[i + 1, i + L - 1] == L - 1)
                        {
                            dp[i, i + L] = Abs(w[i] - w[i + L]) <= 1 ? L + 1 : L - 1;
                        }
                        for (var j = i + 1; j < i + L; j++)
                        {
                            dp[i, i + L] = Max(dp[i, j] + dp[j + 1, i + L], dp[i, i + L]);
                        }
                    }
                }
                Console.WriteLine(dp[0, n - 1]);
            }

            //Console.Out.Flush();
        }
        struct Edge
        {
            public int from;

            public int to;
            public long dist;
            public Edge(int t, long c)
            {
                from = -1;
                to = t;
                dist = c;
            }
            public Edge(int f, int t, long c)
            {
                from = f;
                to = t;
                dist = c;
            }

        }
    }
    public class Scanner
    {
        public int[] ReadSplitInt()
        {
            return ConvertAll(Console.ReadLine().Split(), int.Parse);
        }
        public long[] ReadSplitLong()
        {
            return ConvertAll(Console.ReadLine().Split(), long.Parse);
        }
        public double[] ReadSplit_Double()
        {
            return ConvertAll(Console.ReadLine().Split(), double.Parse);
        }
    }
    public static class Tool
    {
        static public void Initialize<T>(ref T[] array, T initialvalue)
        {
            for (var i = 0; i < array.Length; i++)
            {
                array[i] = initialvalue;
            }
        }
        static public void Swap<T>(ref T a, ref T b)
        {
            T keep = a;
            a = b;
            b = keep;
        }

        static public void Display<T>(T[,] array2d, int n, int m)
        {
            for (var i = 0; i < n; i++)
            {
                for (var j = 0; j < m; j++)
                {
                    Console.Write($"{array2d[i, j]} ");
                }
                Console.WriteLine();
            }
        }

        static public long LPow(int a, int b)
        {
            return (long)Pow(a, b);
        }
    }
}