using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Numerics;
using System;
using System.Collections.Generic;
using System.Text;

namespace Codeforces.TaskC
{
    public class Task
    {
        void Solve()
        {
            int i;
            var min = 1;
            var max = 9;
            Input.Next(out int n);
            var from = new int[n];
            var to = new int[n];
            for (i = 0; i < n; i++)
            {
                Input.Next(out from[i], out to[i]);
            }

            var map = new Dictionary<int, int>();
            i = 0;

            // start always from getting first person
            var currentFloor = 1;
            var nextFloor = from[0];
            map[Increase(0, to[i])] = from[i] - currentFloor; // from 1st to Nth

            for (i=1; i < n; i++) {
                currentFloor = nextFloor;
                nextFloor = from[i]; // next person
#if DEBUG
                Console.WriteLine($"We are on {currentFloor}. Next passenger on {nextFloor}");
#endif

                var newMap = new Dictionary<int, int>();
                foreach(var pair in map)
                {
                    var state = pair.Key;
                    var _state = ToString(state);
#if DEBUG
                    Console.WriteLine("  State=" + _state);
#endif
                    var time = pair.Value;

                    if (nextFloor >= currentFloor)
                    {
                        for (var bottom = min; bottom <= currentFloor; bottom++)
                        {
                            if (Count(state, bottom) > 0 || bottom == currentFloor)
                            {
                                for (var top = nextFloor; top <= max; top++)
                                {
                                    if (Count(state, top) > 0 || top == nextFloor)
                                    {
                                        var thisTime = time + (top - bottom) + (top - nextFloor) + (currentFloor - bottom);
                                        var cleared = Clear(state, bottom, top);
                                        if (Total(cleared) >= 4)
                                        {
#if DEBUG
                                            Console.WriteLine(" - :-(((((");
#endif
                                            continue;
                                        }
                                        var newState = Increase(cleared, to[i]);
#if DEBUG
                                        var _newState = ToString(newState);
                                        Console.Write($"    - {bottom} => {top} in {thisTime}s with {_newState}");
#endif
                                        if (Total(newState) > 4)
                                        {
#if DEBUG
                                            Console.WriteLine(" - overload");
#endif
                                            continue;
                                        }
                                        if (newMap.TryGetValue(newState, out int otherTime))
                                        {
                                            if (otherTime < thisTime)
                                            {
#if DEBUG
                                                Console.WriteLine(" - too slow");
#endif
                                                continue;
                                            }
                                        }
#if DEBUG
                                        Console.WriteLine(" - OK");
#endif
                                        newMap[newState] = thisTime;
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        for (var bottom = min; bottom <= nextFloor; bottom++)
                        {
                            if (Count(state, bottom) > 0 || bottom == nextFloor)
                            {
                                for (var top = currentFloor; top <= max; top++)
                                {
                                    if (Count(state, top) > 0 || top == currentFloor)
                                    {
                                        var thisTime = time + (top - bottom) + (top - currentFloor) + (nextFloor - bottom);
                                        var newState = Increase(Clear(state, bottom, top), to[i]);
#if DEBUG
                                        var _newState = ToString(newState);
                                        Console.Write($"    - {bottom} => {top} in {thisTime} with {_newState}");
#endif
                                        if (Total(state) > 4) {
#if DEBUG
                                            Console.WriteLine(" - overload");
#endif
                                            continue;
                                        }
                                        if (newMap.TryGetValue(newState, out int otherTime))
                                        {
                                            if (otherTime < thisTime)
                                            {
#if DEBUG
                                                Console.WriteLine(" - too slow");
#endif
                                                continue;
                                            }
                                        }
#if DEBUG
                                        Console.WriteLine(" - OK");
#endif
                                        newMap[newState] = thisTime;
                                    }
                                }
                            }
                        }
                    }
                }

                map = newMap;
            }

            currentFloor = nextFloor;

            int minTime = int.MaxValue;
            foreach (var pair in map)
            {
                var state = pair.Key;
                var time = pair.Value;
                var x = 0;
                var y = 0;
                for (i = min; i < currentFloor; i++)
                {
                    if (Count(state, i) > 0)
                    {
                        x = i;
                        break;
                    }
                }
                for (i = max; i > currentFloor; i--)
                {
                    if (Count(state, i) > 0)
                    {
                        y = i;
                        break;
                    }
                }

                if (x == 0) time += y - currentFloor;
                else if (y == 0) time += currentFloor - x;
                else time += Math.Min(x, y) * 2 + Math.Max(x, y);
                if (time < minTime)
                    minTime = time;
            }

            var result = minTime + 2 * n;
            Console.WriteLine(result);
        }

        public string ToString(int state)
        {
            var b = new StringBuilder();
            for (var i = 9; i >= 1; i--)
            {
                var count = Count(state, i);
                if (count == 0) b.Append(count);
                else b.Append(count);
                if (i % 3 == 1 && i > 1) b.Append(' ');
            }
            return b.ToString();
        }

        struct State
        {
            public int Count;
            public int Time;

            public State(int count, int time)
            {
                Count = count;
                Time = time;
            }
        }

        public static void Main()
        {
            var task = new Task();
#if DEBUG
            task.Solve();
#else
            try
            {
                task.Solve();
            }
            catch (Exception ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(ex);
            }
#endif
        }

        public static int Count(int state, int i)
        {
            var shift = (i-1) * 3;
            return (state & (7 << shift)) >> shift;
        }

        public static int Increase(int state, int i)
        {
            var shift = (i-1) * 3;
            return state + (1 << shift);
        }

        public static int Clear(int state, int from, int to)
        {
            from--;
            to--;
            var mask = ((1 << (3*(to - from + 1))) - 1) << (from * 3);
            mask = -1 ^ mask;
            return state & mask;
        }

        public static int Total(int state)
        {
            return (state & (7))
                + ((state & (7<<3)) >> 3)
                + ((state & (7 << 6)) >> 6)
                + ((state & (7 << 9)) >> 9)
                + ((state & (7 << 12)) >> 12)
                + ((state & (7 << 15)) >> 15)
                + ((state & (7 << 18)) >> 18)
                + ((state & (7 << 21)) >> 21)
                + ((state & (7 << 24)) >> 24)
                + ((state & (7 << 27)) >> 27);
        }
    }
}

namespace Codeforces
{
    public class Input
    {
        private static string _line;

        public static bool Next()
        {
            _line = Console.ReadLine();
            return _line != null;
        }

        public static bool Next(out long a)
        {
            var ok = Next();
            a = ok ? long.Parse(_line) : 0;
            return ok;
        }

        public static bool Next(out long a, out long b)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(long.Parse).ToArray();
                a = array[0];
                b = array[1];
            }
            else
            {
                a = b = 0;
            }

            return ok;
        }

        public static bool Next(out long a, out long b, out long c)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(long.Parse).ToArray();
                a = array[0];
                b = array[1];
                c = array[2];
            }
            else
            {
                a = b = c = 0;
            }
            return ok;
        }

        public static bool Next(out long a, out long b, out long c, out long d)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(long.Parse).ToArray();
                a = array[0];
                b = array[1];
                c = array[2];
                d = array[3];
            }
            else
            {
                a = b = c = d = 0;
            }
            return ok;
        }

        public static bool Next(out long a, out long b, out long c, out long d, out long e)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(long.Parse).ToArray();
                a = array[0];
                b = array[1];
                c = array[2];
                d = array[3];
                e = array[4];
            }
            else
            {
                a = b = c = d = e = 0;
            }
            return ok;
        }

        public static bool Next(out int a)
        {
            var ok = Next();
            a = ok ? int.Parse(_line) : 0;
            return ok;
        }

        public static bool Next(out int a, out int b)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(int.Parse).ToArray();
                a = array[0];
                b = array[1];
            }
            else
            {
                a = b = 0;
            }

            return ok;
        }

        public static bool Next(out int a, out int b, out int c)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(int.Parse).ToArray();
                a = array[0];
                b = array[1];
                c = array[2];
            }
            else
            {
                a = b = c = 0;
            }
            return ok;
        }

        public static bool Next(out int a, out int b, out int c, out int d)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(int.Parse).ToArray();
                a = array[0];
                b = array[1];
                c = array[2];
                d = array[3];
            }
            else
            {
                a = b = c = d = 0;
            }
            return ok;
        }

        public static bool Next(out int a, out int b, out int c, out int d, out int e)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(int.Parse).ToArray();
                a = array[0];
                b = array[1];
                c = array[2];
                d = array[3];
                e = array[4];
            }
            else
            {
                a = b = c = d = e = 0;
            }
            return ok;
        }

        public static bool Next(out int a, out int b, out int c, out int d, out int e, out int f)
        {
            var ok = Next();
            if (ok)
            {
                var array = _line.Split(' ').Select(int.Parse).ToArray();
                a = array[0];
                b = array[1];
                c = array[2];
                d = array[3];
                e = array[4];
                f = array[5];
            }
            else
            {
                a = b = c = d = e = f = 0;
            }
            return ok;
        }

        public static IEnumerable<long> ArrayLong()
        {
            return !Next() ? new List<long>() : _line.Split().Select(long.Parse);
        }

        public static IEnumerable<int> ArrayInt()
        {
            return !Next() ? new List<int>() : _line.Split().Select(int.Parse);
        }

        public static bool Next(out string value)
        {
            value = string.Empty;
            if (!Next()) return false;
            value = _line;
            return true;
        }
    }

    public class DisjointSet
    {
        private readonly int[] _parent;
        private readonly int[] _rank;
        public int Count { get; private set; }

        public DisjointSet(int count, int initialize = 0)
        {
            Count = count;
            _parent = new int[Count];
            _rank = new int[Count];
            for (var i = 0; i < initialize; i++) _parent[i] = i;
        }

        private DisjointSet(int count, int[] parent, int[] rank)
        {
            Count = count;
            _parent = parent;
            _rank = rank;
        }

        public void Add(int v)
        {
            _parent[v] = v;
            _rank[v] = 0;
        }

        public int Find_Recursive(int v)
        {
            if (_parent[v] == v) return v;
            return _parent[v] = Find(_parent[v]);
        }

        public int Find(int v)
        {
            if (_parent[v] == v) return v;
            var last = v;
            while (_parent[last] != last) last = _parent[last];
            while (_parent[v] != v)
            {
                var t = _parent[v];
                _parent[v] = last;
                v = t;
            }
            return last;
        }

        public int this[int v]
        {
            get { return Find(v); }
            set { Union(v, value); }
        }

        public void Union(int a, int b)
        {
            a = Find(a);
            b = Find(b);
            if (a == b) return;
            if (_rank[a] < _rank[b])
            {
                var t = _rank[a];
                _rank[a] = _rank[b];
                _rank[b] = t;
            }
            _parent[b] = a;
            if (_rank[a] == _rank[b]) _rank[a]++;
        }

        public int GetSetCount()
        {
            var result = 0;
            for (var i = 0; i < Count; i++)
            {
                if (_parent[i] == i) result++;
            }
            return result;
        }

        public DisjointSet Clone()
        {
            var rank = new int[Count];
            _rank.CopyTo(rank, 0);
            var parent = new int[Count];
            _parent.CopyTo(parent, 0);
            return new DisjointSet(Count, parent, rank);
        }

        public override string ToString()
        {
            return string.Join(",", _parent.Take(50));
        }
    }

    public class Matrix
    {
        public static Matrix Create(int i, int j)
        {
            var m = new Matrix(i, j);
            return m;
        }

        public static Matrix Create(int i)
        {
            var m = new Matrix(i, i);
            return m;
        }

        public long Modulo { get; set; }

        private readonly int _width;
        private readonly int _height;
        private readonly long[,] _data;
        public int Width { get { return _width; } }
        public int Height { get { return _height; } }

        private Matrix(int i, int j)
        {
            Modulo = 1000000000000000000L;
            _width = j;
            _height = i;
            _data = new long[_height, _width];
        }

        public static Matrix operator *(Matrix m1, Matrix m2)
        {
            if (m1.Width != m2.Height) throw new InvalidDataException("m1.Width != m2.Height");
            var m = Create(m2.Width, m1.Height);
            m.Modulo = m1.Modulo;
            for (var i = 0; i < m2.Width; i++)
                for (var j = 0; j < m1.Height; j++)
                {
                    for (var k = 0; k < m1.Width; k++)
                        m[j, i] += (m1[j, k] * m2[k, i]) % m1.Modulo;
                    m[j, i] %= m1.Modulo;
                }
            return m;
        }

        public static Matrix operator +(Matrix m1, Matrix m2)
        {
            var m = m1.Clone();
            for (var i = 0; i < m2.Width; i++)
                for (var j = 0; j < m1.Height; j++)
                    m[j, i] = (m[j, i] + m2[j, i]) % m1.Modulo;
            return m;
        }

        public static Matrix operator -(Matrix m1, Matrix m2)
        {
            var m = m1.Clone();
            for (var i = 0; i < m2.Width; i++)
                for (var j = 0; j < m1.Height; j++)
                    m[j, i] = (m[j, i] - m2[j, i]) % m1.Modulo;
            return m;
        }

        public static Matrix operator *(Matrix m1, long l)
        {
            var m = m1.Clone();
            for (var i = 0; i < m1.Width; i++)
                for (var j = 0; j < m1.Height; j++)
                    m[j, i] = (m[j, i] * l) % m.Modulo;
            return m;
        }

        public static Matrix operator *(long l, Matrix m1)
        {
            return m1 * l;
        }

        public static Matrix operator +(Matrix m1, long l)
        {
            var m = m1.Clone();
            for (var i = 0; i < m1.Width; i++)
                m[i, i] = (m[i, i] + l) % m.Modulo;
            return m;
        }

        public static Matrix operator +(long l, Matrix m1)
        {
            return m1 + l;
        }

        public static Matrix operator -(Matrix m1, long l)
        {
            return m1 + (-l);
        }

        public static Matrix operator -(long l, Matrix m1)
        {
            var m = m1.Clone() * -1;
            return m + l;
        }

        public Matrix BinPower(long l)
        {
            var n = 1;
            var m = Clone();
            var result = new Matrix(m.Height, m.Width) + 1;
            result.Modulo = m.Modulo;
            while (l != 0)
            {
                var i = l & ~(l - 1);
                l -= i;
                while (n < i)
                {
                    m = m * m;
                    n <<= 1;
                }
                result *= m;
            }
            return result;
        }

        public void Fill(long l)
        {
            l %= Modulo;
            for (var i = 0; i < _height; i++)
                for (var j = 0; j < _width; j++)
                    _data[i, j] = l;
        }

        public Matrix Clone()
        {
            var m = new Matrix(_width, _height);
            Array.Copy(_data, m._data, _data.Length);
            m.Modulo = Modulo;
            return m;
        }

        public long this[int i, int j]
        {
            get { return _data[i, j]; }
            set { _data[i, j] = value % Modulo; }
        }
    }

    public class RedBlackTree<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
    {
        private readonly List<Node> _items;
        private Node _root;
        private readonly IComparer<TKey> _comparer;

        public RedBlackTree(int capacity = 10)
        {
            _items = new List<Node>(capacity);
            _comparer = Comparer<TKey>.Default;
        }

        private Node _search(TKey key)
        {
            var node = _root;
            while (node != null)
            {
                var i = _comparer.Compare(key, node.Key);
                if (i == 0) return node;
                node = i > 0 ? node.Right : node.Left;
            }
            return null;
        }

        /// <summary>
        /// Returns lower or equal key
        /// </summary>
        public TKey Lower(TKey key, TKey notFound = default(TKey))
        {
            var node = _root;
            Node good = null;
            while (node != null)
            {
                var i = _comparer.Compare(key, node.Key);
                if (i == 0) return key;
                if (i > 0)
                {
                    good = node;
                    node = node.Right;
                }
                else
                    node = node.Left;
            }
            return good == null ? notFound : good.Key;
        }

        /// <summary>
        /// Returns higher or equal key
        /// </summary>
        public TKey Higher(TKey key, TKey notFound = default(TKey))
        {
            var node = _root;
            Node good = null;
            while (node != null)
            {
                var i = _comparer.Compare(key, node.Key);
                if (i == 0) return key;
                if (i < 0)
                {
                    good = node;
                    node = node.Left;
                }
                else
                    node = node.Right;
            }
            return good == null ? notFound : good.Key;
        }

        /// <summary>
        /// Returns minimum region, which encloses given key
        /// </summary>
        public Tuple<TKey, TKey> Bounds(TKey key, TKey notFound = default(TKey))
        {
            var node = _root;
            Node lower = null;
            Node higher = null;
            while (node != null)
            {
                var i = _comparer.Compare(key, node.Key);
                if (i == 0) return new Tuple<TKey, TKey>(key, key);
                if (i < 0)
                {
                    higher = node;
                    node = node.Left;
                }
                else
                {
                    lower = node;
                    node = node.Right;
                }
            }
            return new Tuple<TKey, TKey>(lower == null ? notFound : lower.Key, higher == null ? notFound : higher.Key);
        }

        public void Add(TKey key, TValue value)
        {
            var node = new Node { Key = key, Value = value, Red = true };
            _items.Add(node);
            if (_root == null)
            {
                _root = node;
                _root.Red = false;
                return;
            }
            var x = _root;
            Node y = null;
            while (x != null)
            {
                y = x;
                x = _comparer.Compare(key, x.Key) > 0 ? x.Right : x.Left;
            }
            node.Parent = y;
            if (y == null) _root = node;
            else if (_comparer.Compare(key, y.Key) > 0) y.Right = node;
            else y.Left = node;
            InsertFixup(node);
        }

        private void InsertFixup(Node node)
        {
            while (true)
            {
                var parent = node.Parent;
                if (parent == null || !parent.Red || parent.Parent == null) break;
                var grand = parent.Parent;

                if (parent == grand.Left)
                {
                    var uncle = grand.Right;
                    if (uncle != null && uncle.Red) /* parent and uncle both red: we could swap colors of them with grand */
                    {
                        parent.Red = false;
                        uncle.Red = false;
                        grand.Red = true;
                        node = grand; /* and continue fixing tree for grand */
                    }
                    else if (node == parent.Right) /* we rotate around the parent */
                    {
                        node = parent;
                        RotateLeft(node);
                    }
                    else /* rotate around grand and switch colors of grand and parent */
                    {
                        parent.Red = false;
                        grand.Red = true;
                        RotateRight(grand);
                        if (grand == _root) _root = parent;
                        break; /* and finish since tree is fixed */
                    }
                }
                else
                {
                    if (_root.Parent != null) Debugger.Break();

                    var uncle = grand.Left;
                    if (uncle != null && uncle.Red) /* parent and uncle both red: we could swap colors of them with grand */
                    {
                        parent.Red = false;
                        uncle.Red = false;
                        grand.Red = true;
                        node = grand; /* and continue fixing tree for grand */
                    }
                    else if (node == parent.Left) /* we rotate around the parent */
                    {
                        node = parent;
                        RotateRight(node);
                    }
                    else /* rotate around grand and switch colors of grand and parent */
                    {
                        parent.Red = false;
                        grand.Red = true;
                        RotateLeft(grand);
                        if (grand == _root) _root = parent;
                        break; /* and finish since tree is fixed */
                    }
                }
            }
            _root.Red = false;
        }

        private void RotateLeft(Node node)
        {
            if (node.Right == null)
                throw new NotSupportedException("Cannot rotate left: right node is missing");
            var parent = node.Parent;
            var right = node.Right;
            right.Parent = parent;
            if (parent != null)
            {
                if (parent.Left == node) parent.Left = right;
                else parent.Right = right;
            }
            node.Right = right.Left;
            if (node.Right != null)
                node.Right.Parent = node;
            right.Left = node;
            node.Parent = right;
        }

        private void RotateRight(Node node)
        {
            if (node.Left == null)
                throw new NotSupportedException("Cannot rotate right: left node is missing");
            var parent = node.Parent;
            var left = node.Left;
            left.Parent = parent;
            if (parent != null)
            {
                if (parent.Left == node) parent.Left = left;
                else parent.Right = left;
            }
            node.Left = left.Right;
            if (node.Left != null)
                node.Left.Parent = node;
            left.Right = node;
            node.Parent = left;
        }

        public void Remove(TKey key)
        {
            var node = _search(key);
            if (node == null) return;

            var deleted = node.Left == null || node.Right == null ? node : Next(node);
            var child = deleted.Left ?? deleted.Right;
            if (child != null)
                child.Parent = deleted.Parent;
            if (deleted.Parent == null) /* root */
                _root = child;
            else if (deleted == deleted.Parent.Left)
                deleted.Parent.Left = child;
            else
                deleted.Parent.Right = child;
            if (node != deleted)
            {
                node.Key = deleted.Key;
                node.Value = deleted.Value;
            }

            if (!deleted.Red)
            {
                DeleteFixup(child, deleted.Parent);
            }
        }

        private void DeleteFixup(Node node, Node parent)
        {
            while (parent != null && (node == null || !node.Red))
            {
                if (node == parent.Left)
                {
                    var brother = parent.Right;
                    if (brother.Red)
                    {
                        brother.Red = false;
                        parent.Red = true;
                        RotateLeft(parent);
                        brother = parent.Right;
                    }
                    if ((brother.Left == null || !brother.Left.Red) && (brother.Right == null || !brother.Right.Red))
                    {
                        node = parent.Red ? _root : parent;
                        brother.Red = true;
                        parent.Red = false;
                    }
                    else
                    {
                        if (brother.Right == null || !brother.Right.Red)
                        {
                            if (brother.Left != null)
                                brother.Left.Red = false;
                            brother.Red = true;
                            RotateRight(brother);
                            brother = parent.Right;
                        }
                        if (!brother.Right.Red) Debugger.Break();
                        brother.Red = parent.Red;
                        parent.Red = false;
                        if (brother.Right != null)
                            brother.Right.Red = false;
                        RotateLeft(parent);
                        node = _root;
                    }
                }
                else
                {
                    var brother = parent.Left;
                    if (brother.Red)
                    {
                        brother.Red = false;
                        parent.Red = true;
                        RotateRight(parent);
                        brother = parent.Left;
                    }
                    if ((brother.Right == null || !brother.Right.Red) && (brother.Left == null || !brother.Left.Red))
                    {
                        node = parent.Red ? _root : parent;
                        brother.Red = true;
                        parent.Red = false;
                    }
                    else
                    {
                        if (brother.Left == null || !brother.Left.Red)
                        {
                            if (brother.Right != null)
                                brother.Right.Red = false;
                            brother.Red = true;
                            RotateLeft(brother);
                            brother = parent.Left;
                        }
                        brother.Red = parent.Red;
                        parent.Red = false;
                        if (brother.Left != null)
                            brother.Left.Red = false;
                        RotateRight(parent);
                        node = _root;
                    }
                }
                parent = node.Parent;
            }

            node.Red = false;
        }

        public TValue this[TKey key]
        {
            get
            {
                var node = _search(key);
                return node == null ? default(TValue) : node.Value;
            }
            set
            {
                var node = _search(key);
                if (node == null) Add(key, value);
                else node.Value = value;
            }
        }

        public bool Check()
        {
            int count;
            return _root == null || _root.Check(out count);
        }

        private Node Minimum(Node node)
        {
            var result = node;
            while (result.Left != null) result = result.Left;
            return result;
        }

        private Node Maximum(Node node)
        {
            var result = node;
            while (result.Right != null) result = result.Right;
            return result;
        }

        private Node Next(Node node)
        {
            Node result;
            if (node.Right != null)
            {
                result = Minimum(node.Right);
            }
            else
            {
                while (node.Parent != null && node.Parent.Right == node)
                    node = node.Parent;
                result = node.Parent;
            }
            return result;
        }

        private Node Previous(Node node)
        {
            Node result;
            if (node.Left != null)
            {
                result = Maximum(node.Left);
            }
            else
            {
                while (node.Parent != null && node.Parent.Left == node)
                    node = node.Parent;
                result = node.Parent;
            }
            return result;
        }

        public void Print()
        {
            var node = Minimum(_root);
            while (node != null)
            {
                Console.Write(node.Red ? '*' : ' ');
                Console.Write(node.Key);
                Console.Write('\t');
                node = Next(node);
            }
        }

        #region Nested classes

        [DebuggerDisplay("{ToString()}")]
        private sealed class Node
        {
            public TKey Key;
            public TValue Value;
            public bool Red;

            public Node Parent;
            public Node Left;
            public Node Right;

            public bool Check(out int count)
            {
                count = 0;
                if (Red)
                {
                    if (Left != null && Left.Red) return false;
                    if (Right != null && Right.Red) return false;
                }
                var left = 0;
                var right = 0;
                if (Left != null && !Left.Check(out left)) return false;
                if (Right != null && !Right.Check(out right)) return false;
                count = left + (Red ? 0 : 1);
                if (left != right)
                {
                    ;
                }
                return left == right;
            }

            public override string ToString()
            {
                return ToShortString(2);
            }

            private string ToShortString(int depth = 0)
            {
                return depth == 0
                    ? string.Format("{0}{1}", Red ? "*" : "", Key)
                    : string.Format("({1}<{0}>{2})", ToShortString(), Left == null ? "null" : Left.ToShortString(depth - 1), Right == null ? "null" : Right.ToShortString(depth - 1));
            }
        }

        #endregion

        #region IEnumerable

        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
        {
            throw new NotImplementedException();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion
    }

    public class RedBlackTreeSimple<TKey>
    {
        private readonly List<Node> _items;
        private Node _root;
        private readonly IComparer<TKey> _comparer;

        public RedBlackTreeSimple(int capacity = 10)
        {
            _items = new List<Node>(capacity);
            _comparer = Comparer<TKey>.Default;
        }

        private Node _search(TKey key)
        {
            var node = _root;
            while (node != null)
            {
                var i = _comparer.Compare(key, node.Key);
                if (i == 0) return node;
                node = i > 0 ? node.Right : node.Left;
            }
            return null;
        }

        /// <summary>
        /// Returns lower or equal key
        /// </summary>
        public TKey Lower(TKey key, TKey notFound = default(TKey))
        {
            var node = _root;
            Node good = null;
            while (node != null)
            {
                var i = _comparer.Compare(key, node.Key);
                if (i == 0) return key;
                if (i > 0)
                {
                    good = node;
                    node = node.Right;
                }
                else
                    node = node.Left;
            }
            return good == null ? notFound : good.Key;
        }

        /// <summary>
        /// Returns higher or equal key
        /// </summary>
        public TKey Higher(TKey key, TKey notFound = default(TKey))
        {
            var node = _root;
            Node good = null;
            while (node != null)
            {
                var i = _comparer.Compare(key, node.Key);
                if (i == 0) return key;
                if (i < 0)
                {
                    good = node;
                    node = node.Left;
                }
                else
                    node = node.Right;
            }
            return good == null ? notFound : good.Key;
        }

        /// <summary>
        /// Returns minimum region, which encloses given key
        /// </summary>
        public Tuple<TKey, TKey> Bounds(TKey key, TKey notFound = default(TKey))
        {
            var node = _root;
            Node lower = null;
            Node higher = null;
            while (node != null)
            {
                var i = _comparer.Compare(key, node.Key);
                if (i == 0) return new Tuple<TKey, TKey>(key, key);
                if (i < 0)
                {
                    higher = node;
                    node = node.Left;
                }
                else
                {
                    lower = node;
                    node = node.Right;
                }
            }
            return new Tuple<TKey, TKey>(lower == null ? notFound : lower.Key, higher == null ? notFound : higher.Key);
        }

        public void Add(TKey key)
        {
            var node = new Node(key);
            _items.Add(node);
            if (_root == null)
            {
                _root = node;
                _root.Red = false;
                return;
            }
            var x = _root;
            Node y = null;
            while (x != null)
            {
                y = x;
                x = _comparer.Compare(key, x.Key) > 0 ? x.Right : x.Left;
            }
            node.Parent = y;
            if (y == null) _root = node;
            else if (_comparer.Compare(key, y.Key) > 0) y.Right = node;
            else y.Left = node;
            InsertFixup(node);
        }

        private void InsertFixup(Node node)
        {
            while (true)
            {
                var parent = node.Parent;
                if (parent == null || !parent.Red || parent.Parent == null) break;
                var grand = parent.Parent;

                if (parent == grand.Left)
                {
                    var uncle = grand.Right;
                    if (uncle != null && uncle.Red) /* parent and uncle both red: we could swap colors of them with grand */
                    {
                        parent.Red = false;
                        uncle.Red = false;
                        grand.Red = true;
                        node = grand; /* and continue fixing tree for grand */
                    }
                    else if (node == parent.Right) /* we rotate around the parent */
                    {
                        node = parent;
                        RotateLeft(node);
                    }
                    else /* rotate around grand and switch colors of grand and parent */
                    {
                        parent.Red = false;
                        grand.Red = true;
                        RotateRight(grand);
                        if (grand == _root) _root = parent;
                        break; /* and finish since tree is fixed */
                    }
                }
                else
                {
                    if (_root.Parent != null) Debugger.Break();

                    var uncle = grand.Left;
                    if (uncle != null && uncle.Red) /* parent and uncle both red: we could swap colors of them with grand */
                    {
                        parent.Red = false;
                        uncle.Red = false;
                        grand.Red = true;
                        node = grand; /* and continue fixing tree for grand */
                    }
                    else if (node == parent.Left) /* we rotate around the parent */
                    {
                        node = parent;
                        RotateRight(node);
                    }
                    else /* rotate around grand and switch colors of grand and parent */
                    {
                        parent.Red = false;
                        grand.Red = true;
                        RotateLeft(grand);
                        if (grand == _root) _root = parent;
                        break; /* and finish since tree is fixed */
                    }
                }
            }
            _root.Red = false;
        }

        private void RotateLeft(Node node)
        {
            if (node.Right == null)
                throw new NotSupportedException("Cannot rotate left: right node is missing");
            var parent = node.Parent;
            var right = node.Right;
            right.Parent = parent;
            if (parent != null)
            {
                if (parent.Left == node) parent.Left = right;
                else parent.Right = right;
            }
            node.Right = right.Left;
            if (node.Right != null)
                node.Right.Parent = node;
            right.Left = node;
            node.Parent = right;
        }

        private void RotateRight(Node node)
        {
            if (node.Left == null)
                throw new NotSupportedException("Cannot rotate right: left node is missing");
            var parent = node.Parent;
            var left = node.Left;
            left.Parent = parent;
            if (parent != null)
            {
                if (parent.Left == node) parent.Left = left;
                else parent.Right = left;
            }
            node.Left = left.Right;
            if (node.Left != null)
                node.Left.Parent = node;
            left.Right = node;
            node.Parent = left;
        }

        public void Remove(TKey key)
        {
            var node = _search(key);
            if (node == null) return;

            var deleted = node.Left == null || node.Right == null ? node : Next(node);
            var child = deleted.Left ?? deleted.Right;
            if (child != null)
                child.Parent = deleted.Parent;
            if (deleted.Parent == null) /* root */
                _root = child;
            else if (deleted == deleted.Parent.Left)
                deleted.Parent.Left = child;
            else
                deleted.Parent.Right = child;
            if (node != deleted)
            {
                node.Key = deleted.Key;
            }

            if (!deleted.Red)
            {
                DeleteFixup(child, deleted.Parent);
            }
        }

        private void DeleteFixup(Node node, Node parent)
        {
            while (parent != null && (node == null || !node.Red))
            {
                if (node == parent.Left)
                {
                    var brother = parent.Right;
                    if (brother.Red)
                    {
                        brother.Red = false;
                        parent.Red = true;
                        RotateLeft(parent);
                        brother = parent.Right;
                    }
                    if ((brother.Left == null || !brother.Left.Red) && (brother.Right == null || !brother.Right.Red))
                    {
                        node = parent.Red ? _root : parent;
                        brother.Red = true;
                        parent.Red = false;
                    }
                    else
                    {
                        if (brother.Right == null || !brother.Right.Red)
                        {
                            if (brother.Left != null)
                                brother.Left.Red = false;
                            brother.Red = true;
                            RotateRight(brother);
                            brother = parent.Right;
                        }
                        if (!brother.Right.Red) Debugger.Break();
                        brother.Red = parent.Red;
                        parent.Red = false;
                        if (brother.Right != null)
                            brother.Right.Red = false;
                        RotateLeft(parent);
                        node = _root;
                    }
                }
                else
                {
                    var brother = parent.Left;
                    if (brother.Red)
                    {
                        brother.Red = false;
                        parent.Red = true;
                        RotateRight(parent);
                        brother = parent.Left;
                    }
                    if ((brother.Right == null || !brother.Right.Red) && (brother.Left == null || !brother.Left.Red))
                    {
                        node = parent.Red ? _root : parent;
                        brother.Red = true;
                        parent.Red = false;
                    }
                    else
                    {
                        if (brother.Left == null || !brother.Left.Red)
                        {
                            if (brother.Right != null)
                                brother.Right.Red = false;
                            brother.Red = true;
                            RotateLeft(brother);
                            brother = parent.Left;
                        }
                        brother.Red = parent.Red;
                        parent.Red = false;
                        if (brother.Left != null)
                            brother.Left.Red = false;
                        RotateRight(parent);
                        node = _root;
                    }
                }
                parent = node.Parent;
            }

            node.Red = false;
        }

        private Node Minimum(Node node)
        {
            var result = node;
            while (result.Left != null) result = result.Left;
            return result;
        }

        private Node Maximum(Node node)
        {
            var result = node;
            while (result.Right != null) result = result.Right;
            return result;
        }

        private Node Next(Node node)
        {
            Node result;
            if (node.Right != null)
            {
                result = Minimum(node.Right);
            }
            else
            {
                while (node.Parent != null && node.Parent.Right == node)
                    node = node.Parent;
                result = node.Parent;
            }
            return result;
        }

        private Node Previous(Node node)
        {
            Node result;
            if (node.Left != null)
            {
                result = Maximum(node.Left);
            }
            else
            {
                while (node.Parent != null && node.Parent.Left == node)
                    node = node.Parent;
                result = node.Parent;
            }
            return result;
        }

        public void Print()
        {
            var node = Minimum(_root);
            while (node != null)
            {
                Console.Write(node.Red ? '*' : ' ');
                Console.Write(node.Key);
                Console.Write('\t');
                node = Next(node);
            }
        }

        #region Nested classes

        private sealed class Node
        {
            public Node(TKey key)
            {
                Key = key;
            }

            public TKey Key;
            public bool Red = true;

            public Node Parent;
            public Node Left;
            public Node Right;
        }

        #endregion
    }

    /// <summary>
    /// Fenwick tree for summary on the array
    /// </summary>
    public class FenwickSum
    {
        public readonly int Size;
        private readonly int[] _items;
        public FenwickSum(int size)
        {
            Size = size;
            _items = new int[Size];
        }

        public FenwickSum(IList<int> items)
            : this(items.Count)
        {
            for (var i = 0; i < Size; i++)
                Increase(i, items[i]);
        }

        private int Sum(int r)
        {
            if (r < 0) return 0;
            if (r >= Size) r = Size - 1;
            var result = 0;
            for (; r >= 0; r = (r & (r + 1)) - 1)
                result += _items[r];
            return result;
        }

        private int Sum(int l, int r)
        {
            return Sum(r) - Sum(l - 1);
        }

        public int this[int r]
        {
            get { return Sum(r); }
        }

        public int this[int l, int r]
        {
            get { return Sum(l, r); }
        }

        public void Increase(int i, int delta)
        {
            for (; i < Size; i = i | (i + 1))
                _items[i] += delta;
        }
    }

    /// <summary>
    /// Prime numbers
    /// </summary>
    public class Primes
    {
        /// <summary>
        /// Returns prime numbers in O(n)
        /// Returns lowet divisors as well
        /// Memory O(n)
        /// </summary>
        public static void ImprovedSieveOfEratosthenes(int n, out int[] lp, out List<int> pr)
        {
            lp = new int[n];
            pr = new List<int>();
            for (var i = 2; i < n; i++)
            {
                if (lp[i] == 0)
                {
                    lp[i] = i;
                    pr.Add(i);
                }
                foreach (var prJ in pr)
                {
                    var prIj = i * prJ;
                    if (prJ <= lp[i] && prIj <= n - 1)
                    {
                        lp[prIj] = prJ;
                    }
                    else
                    {
                        break;
                    }
                }
            }
        }

        /// <summary>
        /// Returns prime numbers in O(n*n)
        /// </summary>
        public static void SieveOfEratosthenes(int n, out List<int> pr)
        {
            var m = 50000;//(int)(3l*n/(long)Math.Log(n)/2);
            pr = new List<int>();
            var f = new bool[m];
            for (var i = 2; i * i <= n; i++)
                if (!f[i])
                    for (var j = (long)i * i; j < m && j * j < n; j += i)
                        f[j] = true;
            pr.Add(2);
            for (var i = 3; i * i <= n; i += 2)
                if (!f[i])
                    pr.Add(i);
        }

        /// <summary>
        /// Greatest common divisor
        /// </summary>
        public static int Gcd(int x, int y)
        {
            while (y != 0)
            {
                var c = y;
                y = x % y;
                x = c;
            }
            return x;
        }

        /// <summary>
        /// Greatest common divisor
        /// </summary>
        public static long Gcd(long x, long y)
        {
            while (y != 0)
            {
                var c = y;
                y = x % y;
                x = c;
            }
            return x;
        }

        /// <summary>
        /// Greatest common divisor
        /// </summary>
        public static BigInteger Gcd(BigInteger x, BigInteger y)
        {
            while (y != 0)
            {
                var c = y;
                y = x % y;
                x = c;
            }
            return x;
        }

        /// <summary>
        /// Returns all divisors of n in O(√n)
        /// </summary>
        public static IEnumerable<long> GetDivisors(long n)
        {
            long r;
            while (true)
            {
                var x = Math.DivRem(n, 2, out r);
                if (r != 0) break;
                n = x;
                yield return 2;
            }
            var i = 3;
            while (i <= Math.Sqrt(n))
            {
                var x = Math.DivRem(n, i, out r);
                if (r == 0)
                {
                    n = x;
                    yield return i;
                }
                else i += 2;
            }
            if (n != 1) yield return n;
        }
    }

    /// <summary>
    /// Graph matching algorithms
    /// </summary>
    public class GraphMatching
    {
        #region Kuhn algorithm

        /// <summary>
        /// Kuhn algorithm for finding maximal matching
        /// in bipartite graph
        /// Vertexes are numerated from zero: 0, 1, 2, ... n-1
        /// Return array of matchings
        /// </summary>
        public static int[] Kuhn(List<int>[] g, int leftSize, int rightSize)
        {
            Debug.Assert(g.Count() == leftSize);

            var matching = new int[leftSize];
            for (var i = 0; i < rightSize; i++)
                matching[i] = -1;
            var used = new bool[leftSize];

            for (var v = 0; v < leftSize; v++)
            {
                Array.Clear(used, 0, leftSize);
                _kuhn_dfs(v, g, matching, used);
            }

            return matching;
        }

        private static bool _kuhn_dfs(int v, List<int>[] g, int[] matching, bool[] used)
        {
            if (used[v]) return false;
            used[v] = true;
            for (var i = 0; i < g[v].Count; i++)
            {
                var to = g[v][i];
                if (matching[to] == -1 || _kuhn_dfs(matching[to], g, matching, used))
                {
                    matching[to] = v;
                    return true;
                }
            }
            return false;
        }

        #endregion
    }
}


# python3
import sys
from itertools import chain
from collections import namedtuple

def readline(): return map(int, input().split())

def readlines():
    for line in sys.stdin.readlines():
        yield map(int, line.split())

class Position(namedtuple('Position', 'payload time')):
    # def __eq__(self, other):
    #     return self.time == other.time \
    #            and sorted(self.payload) == sorted(other.payload)

    def hook(self, start, pivot, a, b):
        lo, up = min(pivot, a), max(pivot, a)
        return Position(tuple(x for x in self.payload if x < lo or up < x)
                        + (b,),
                        self.time + abs(start - pivot) + abs(pivot - a))

    def possibilities_to_take_next(self, floor, a, b):
        shortest = self.hook(floor, floor, a, b)
        if len(shortest.payload) < 5:
            yield shortest

        if floor > a:
            pivots = (x for x in self.payload if x > floor)
        elif floor == a:
            pivots = self.payload
        else:
            pivots = (x for x in self.payload if x < floor)

        for pivot in pivots:
            possibility = self.hook(floor, pivot, a, b)
            yield possibility

    def time_to_get_free(self, floor):
        if self.payload:
            lo, up = min(self.payload), max(self.payload)
            return self.time + abs(lo-up) + min(abs(floor-lo), abs(floor-up))
        else:
            return self.time

def main():
    n, = readline()

    floor = 1
    positions = [Position(payload=(), time=0)]
    for (a, b) in readlines():
        max_acceptable_time = min(pos.time for pos in positions) \
                              + 16 - abs(floor - a)
        positions = [
            possibility for possibility in chain.from_iterable(
                p.possibilities_to_take_next(floor, a, b) for p in positions
            ) if possibility.time <= max_acceptable_time
        ]
        floor = a

    return min(p.time_to_get_free(floor) for p in positions) + 2 * n

print(main())


# python3
import sys
from itertools import chain
from collections import namedtuple

def readline(): return map(int, input().split())

def readlines():
    for line in sys.stdin.readlines():
        yield map(int, line.split())

class Position(namedtuple('Position', 'payload time')):
    # def __eq__(self, other):
    #     return self.time == other.time \
    #            and sorted(self.payload) == sorted(other.payload)

    def is_not_full(self):
        return len(self.payload) < 4

    def take(self, b):
        self.payload.append(b)
        return self

    def free(self, x, y):
        x, y = sorted((x, y))
        return [s for s in self.payload if not x <= s <= y]

    def hook(self, start, pivot, finish):
        time = self.time + abs(start - pivot) + abs(pivot - finish)
        return Position(self.free(pivot, finish), time)

    def possibilities_to_take_next(self, floor, a, b):
        pivots = [x for x in self.payload if x > floor] \
                 if a < floor else \
                 [x for x in self.payload if x < floor] \
                 if a > floor else \
                 [] if self.is_not_full() else list(self.payload)
        pivots.append(floor)

        for pivot in pivots:
            possibility = self.hook(floor, pivot, a)
            if possibility.is_not_full():
                yield possibility.take(b)

    def time_to_get_free(self, floor):
        if self.payload:
            lo, up = min(self.payload), max(self.payload)
            return self.time + abs(lo-up) + min(abs(floor-lo), abs(floor-up))
        else:
            return self.time

# assert sorted(Position(payload=[1, 2, 3, 3, 4, 5, 5, 6, 7], time=3)
#               .free(3, 5)) == [1, 2, 6, 7]

# assert Position(payload=[1, 2, 3, 3, 4, 5, 5, 6, 7], time=3)\
#        .hook(4, 2, 6) == Position(payload=[1, 7], time=9)

# assert Position(payload=[1, 5], time=0)\
#        .take(9) == Position(payload=[1, 5, 9], time=0)

# assert list(Position(payload=[1, 2, 5], time=0)
#             .possibilities_to_take_next(4, 2, 9))\
#        == [Position(payload=[1, 9], time=4),
#            Position(payload=[1, 5, 9], time=2)]

# assert list(Position(payload=[1, 2, 5], time=0)
#             .possibilities_to_take_next(4, 5, 1)) \
#        == [Position(payload=[1], time=7),
#            Position(payload=[1, 1], time=5),
#            Position(payload=[1, 1, 2], time=1)]

def main():
    n, = readline()

    floor = 1
    positions = [Position(payload=[], time=0)]
    for (a, b) in readlines():
        max_accepted_time = (
            min(pos.time for pos in positions)
            + (18 - floor - a if floor > a else floor + a - 2)
        )
        positions = [
            p for p in chain.from_iterable(
                p.possibilities_to_take_next(floor, a, b) for p in positions
            ) if p.time <= max_accepted_time
        ]
        floor = a

    return min(pos.time_to_get_free(floor) for pos in positions) + 2 * n

print(main())


# python3
import sys
from itertools import chain
from collections import namedtuple

def readline(): return map(int, input().split())

def readlines():
    for line in sys.stdin.readlines():
        yield map(int, line.split())

class Position(namedtuple('Position', 'payload time')):
    # def __eq__(self, other):
    #     return self.time == other.time \
    #            and sorted(self.payload) == sorted(other.payload)

    def hook(self, start, pivot, a, b):
        points = (start, pivot, a)
        lo, up = min(points), max(points)
        return Position(tuple(x for x in self.payload if not lo <= x <= up)
                        + (b,),
                        self.time + abs(start - pivot) + abs(pivot - a))

    def possibilities_to_take_next(self, floor, a, b):
        shortest = self.hook(floor, floor, a, b)
        if len(shortest.payload) < 5:
            yield shortest

        for pivot in self.payload:
            possibility = self.hook(floor, pivot, a, b)
            yield possibility

    def time_to_get_free(self, floor):
        if self.payload:
            lo, up = min(self.payload), max(self.payload)
            return self.time + abs(lo-up) + min(abs(floor-lo), abs(floor-up))
        else:
            return self.time

def main():
    n, = readline()

    floor = 1
    positions = [Position(payload=(), time=0)]
    for (a, b) in readlines():
        max_acceptable_time = min(pos.time for pos in positions) + 16
        positions = [
            possibility for possibility in chain.from_iterable(
                p.possibilities_to_take_next(floor, a, b) for p in positions
            ) if possibility.time <= max_acceptable_time
        ]
        floor = a

    return min(p.time_to_get_free(floor) for p in positions) + 2 * n

print(main())


# python3
import sys
from itertools import chain
from collections import namedtuple

def readline(): return map(int, input().split())

def readlines():
    for line in sys.stdin.readlines():
        yield map(int, line.split())

class Position(namedtuple('Position', 'payload time')):
    # def __eq__(self, other):
    #     return self.time == other.time \
    #            and sorted(self.payload) == sorted(other.payload)

    def is_not_full(self):
        return len(self.payload) < 4

    def take(self, b):
        self.payload.append(b)
        return self

    def free(self, x, y):
        x, y = sorted((x, y))
        return [s for s in self.payload if not x <= s <= y]

    def hook(self, start, pivot, finish):
        time = self.time + abs(start - pivot) + abs(pivot - finish)
        return Position(self.free(pivot, finish), time)

    def possibilities_to_take_next(self, floor, a, b):
        pivots = [x for x in self.payload if x > floor] \
                 if a < floor else \
                 [x for x in self.payload if x < floor] \
                 if a > floor else \
                 [] if self.is_not_full() else list(self.payload)
        pivots.append(floor)

        for pivot in pivots:
            possibility = self.hook(floor, pivot, a)
            if possibility.is_not_full():
                yield possibility.take(b)

    def time_to_get_free(self, floor):
        if self.payload:
            lo, up = min(self.payload), max(self.payload)
            return self.time + abs(lo-up) + min(abs(floor-lo), abs(floor-up))
        else:
            return self.time

# assert sorted(Position(payload=[1, 2, 3, 3, 4, 5, 5, 6, 7], time=3)
#               .free(3, 5)) == [1, 2, 6, 7]

# assert Position(payload=[1, 2, 3, 3, 4, 5, 5, 6, 7], time=3)\
#        .hook(4, 2, 6) == Position(payload=[1, 7], time=9)

# assert Position(payload=[1, 5], time=0)\
#        .take(9) == Position(payload=[1, 5, 9], time=0)

# assert list(Position(payload=[1, 2, 5], time=0)
#             .possibilities_to_take_next(4, 2, 9))\
#        == [Position(payload=[1, 9], time=4),
#            Position(payload=[1, 5, 9], time=2)]

# assert list(Position(payload=[1, 2, 5], time=0)
#             .possibilities_to_take_next(4, 5, 1)) \
#        == [Position(payload=[1], time=7),
#            Position(payload=[1, 1], time=5),
#            Position(payload=[1, 1, 2], time=1)]

def main():
    n, = readline()

    floor = 1
    positions = [Position(payload=[], time=0)]
    for (a, b) in readlines():
        max_accepted_time = min(pos.time for pos in positions) + 16
        positions = [
            p for p in chain.from_iterable(
                p.possibilities_to_take_next(floor, a, b) for p in positions
            ) if p.time <= max_accepted_time
        ]
        floor = a

    return min(pos.time_to_get_free(floor) for pos in positions) + 2 * n

print(main())


# python3
import sys
from collections import namedtuple

def readline(): return map(int, input().split())

def readlines():
    for line in sys.stdin.readlines():
        yield map(int, line.split())

class State(namedtuple('State', 'payload time')):
    def hook(self, floor, pivot, a, b):
        lo, up = min(pivot, a), max(pivot, a)
        return State(tuple(sorted(tuple(
                         x for x in self.payload if x < lo or up < x) + (b,))),
                     self.time + abs(floor - pivot) + abs(pivot - a))

    def choices_to_take_next(self, floor, a, b):
        shortest = self.hook(floor, floor, a, b)
        if len(shortest.payload) < 5:
            yield shortest.payload, shortest.time

        if floor > a:
            pivots = (x for x in self.payload if x > floor)
        elif floor == a:
            pivots = self.payload if len(self.payload) == 4 else ()
        else:
            pivots = (x for x in self.payload if x < floor)

        for pivot in pivots:
            possibility = self.hook(floor, pivot, a, b)
            yield possibility.payload, possibility.time

def time_to_get_free(payload, floor):
    if payload:
        lo, up = min(payload), max(payload)
        return abs(lo-up) + min(abs(floor-lo), abs(floor-up))
    else:
        return 0

def main():
    n, = readline()

    floor = 1
    positions = {(): 0}
    for (a, b) in readlines():
        max_acceptable_time = min(positions.values()) + 16 - abs(floor - a)

        new_positions = dict()
        for payload, time in positions.items():
            state = State(payload, time)
            for npayload, ntime in state.choices_to_take_next(floor, a, b):
                if ntime <= max_acceptable_time:
                    if new_positions.setdefault(npayload, ntime) > ntime:
                        new_positions[npayload] = ntime

        positions = new_positions
        floor = a

    return min(t + time_to_get_free(p, floor) for p, t in positions.items()) \
        + 2 * n

print(main())


# python3
import sys
from collections import namedtuple

def readline(): return map(int, input().split())

def readlines():
    for line in sys.stdin.readlines():
        yield map(int, line.split())

class State(namedtuple('State', 'payload time floor')):
    def hook(self, pivot, a, b):
        lo, up = min(pivot, a, self.floor), max(pivot, a, self.floor)
        return tuple(x for x in self.payload if x < lo or up < x) + (b,), \
            self.time + abs(self.floor - pivot) + abs(pivot - a)

    def choices_to_take_next(self, a, b):
        floor = self.floor

        payload, time = self.hook(floor, a, b)
        if len(payload) < 5:
            yield payload, time
            if floor > a:
                pivots = (x for x in self.payload if x > floor)
            elif floor == a:
                pivots = ()
            else:
                pivots = (x for x in self.payload if x < floor)
        else:
            pivots = self.payload

        for pivot in pivots:
            yield self.hook(pivot, a, b)

def time_to_get_free(payload, floor):
    if payload:
        lo, up = min(payload), max(payload)
        return abs(lo-up) + min(abs(floor-lo), abs(floor-up))
    else:
        return 0

def main():
    n, = readline()

    floor = 1
    positions = {(): 0}  # empty elevator, time = 0
    for (a, b) in readlines():
        max_acceptable_time = min(positions.values()) + 16 - abs(floor - a)

        new_positions = dict()
        for payload, time in positions.items():
            state = State(payload, time, floor)
            for npayload, ntime in state.choices_to_take_next(a, b):
                if ntime <= max_acceptable_time:
                    npayload = tuple(sorted(npayload))
                    if new_positions.setdefault(npayload, ntime) > ntime:
                        new_positions[npayload] = ntime

        positions = new_positions
        floor = a

    return min(t + time_to_get_free(p, floor) for p, t in positions.items()) \
        + 2 * n

print(main())


# python3
from copy import copy
from itertools import chain
from bisect import bisect_left as lower_bound, bisect_right as upper_bound, \
                   insort

def readline(): return map(int, input().split())

def readlines(count): return (readline() for __ in range(count))

class Slots(object):
    def __init__(self, **kwargs):
        for (key, value) in kwargs.items():
            setattr(self, key, value)

    def __iter__(self):
        for slot in self.__slots__:
            yield slot, copy(getattr(self, slot))

    #def __eq__(self, other):
        #return all(getattr(self, slot) == getattr(other, slot)
                   #for slot in self.__slots__)

    #def __repr__(self):
        #return f"{self.__class__.__name__}(" \
               #+ ", ".join(f"{k}={v}" for (k, v) in self) + ")"

    def copy(self):
        return self.__class__(**dict(self))

class Position(Slots):
    __slots__ = 'floor payload time'.split()

    def is_not_full(self):
        return len(self.payload) < 4

    def take(self, b):
        insort(self.payload, b)
        return self

    def free(self, x, y):
        lo = lower_bound(self.payload, min(x, y))
        up = upper_bound(self.payload, max(x, y))
        del self.payload[lo:up]
        return self

    def hook(self, pivot, finish):
        self.time += abs(self.floor - pivot) + abs(pivot - finish)
        self.floor = finish
        self.free(*sorted([pivot, finish]))
        return self

    def possibilities_to_take_next(self, a, b):
        pivots = self.payload[upper_bound(self.payload, self.floor):] \
                 if a <= self.floor else \
                 self.payload[:lower_bound(self.payload, self.floor)]
        pivots.append(self.floor)

        for pivot in pivots:
            possibility = self.copy().hook(pivot, a)
            if possibility.is_not_full():
                yield possibility.take(b)

    def get_free(self):
        if self.payload:
            lo, up = self.payload[0], self.payload[-1]
            if self.floor <= (lo + up) // 2:
                self.hook(lo, up)
            else:
                self.hook(up, lo)
            assert not self.payload
        return self

#assert Position(floor=2, payload=[1, 2, 3, 3, 4, 5, 5, 6, 7], time=3)\
       #.free(3, 5) == Position(floor=2, payload=[1, 2, 6, 7], time=3)

#assert Position(floor=4, payload=[1, 2, 3, 3, 4, 5, 5, 6, 7], time=3)\
       #.hook(2, 6) == Position(floor=6, payload=[1, 7], time=9)

#assert Position(floor=4, payload=[1, 5], time=0)\
       #.take(9) == Position(floor=4, payload=[1, 5, 9], time=0)

#assert list(Position(floor=4, payload=[1, 2, 5], time=0)
            #.possibilities_to_take_next(2, 9))\
       #== [Position(floor=2, payload=[1, 9], time=4),
           #Position(floor=2, payload=[1, 5, 9], time=2)]

#assert list(Position(floor=4, payload=[1, 2, 5], time=0)
            #.possibilities_to_take_next(5, 1)) \
       #== [Position(floor=5, payload=[1], time=7),
           #Position(floor=5, payload=[1, 1], time=5),
           #Position(floor=5, payload=[1, 1, 2], time=1)]

def main():
    n, = readline()

    positions = [Position(floor=1, payload=list(), time=0)]
    for (a, b) in readlines(n):
        positions = list(chain.from_iterable(p.possibilities_to_take_next(a, b)
                                             for p in positions))

    return min(pos.get_free().time for pos in positions) + 2 * n

print(main())


# python3
import sys
from itertools import chain
from collections import namedtuple

def readline(): return map(int, input().split())

def readlines():
    for line in sys.stdin.readlines():
        yield map(int, line.split())

class Position(namedtuple('Position', 'payload time')):
    # def __eq__(self, other):
    #     return self.time == other.time \
    #            and sorted(self.payload) == sorted(other.payload)

    def free(self, x, y):
        x, y = sorted((x, y))
        return tuple(s for s in self.payload if not x <= s <= y)

    def hook(self, start, pivot, a, b):
        return Position(self.free(pivot, a) + (b,),
                        self.time + abs(start - pivot) + abs(pivot - a))

    def possibilities_to_take_next(self, floor, a, b):
        if a == floor:
            pivots = [] if len(self.payload) < 4 else list(self.payload)
        else:
            pivots = [x for x in self.payload if x > floor] \
                     if a < floor else \
                     [x for x in self.payload if x < floor]
        pivots.append(floor)

        for pivot in pivots:
            possibility = self.hook(floor, pivot, a, b)
            if len(possibility.payload) < 5:
                yield possibility

    def time_to_get_free(self, floor):
        if self.payload:
            lo, up = min(self.payload), max(self.payload)
            return self.time + abs(lo-up) + min(abs(floor-lo), abs(floor-up))
        else:
            return self.time

# assert sorted(Position(payload=[1, 2, 3, 3, 4, 5, 5, 6, 7], time=3)
#               .free(3, 5)) == [1, 2, 6, 7]

# assert Position(payload=[1, 2, 3, 3, 4, 5, 5, 6, 7], time=3)\
#        .hook(4, 2, 6, 777) == Position(payload=[1, 7, 777], time=9)

# assert list(Position(payload=[1, 2, 5], time=0)
#             .possibilities_to_take_next(4, 2, 9))\
#        == [Position(payload=[1, 9], time=4),
#            Position(payload=[1, 5, 9], time=2)]

# assert list(Position(payload=[1, 2, 5], time=0)
#             .possibilities_to_take_next(4, 5, 1)) \
#        == [Position(payload=[1], time=7),
#            Position(payload=[1, 1], time=5),
#            Position(payload=[1, 1, 2], time=1)]

def main():
    n, = readline()

    floor = 1
    positions = [Position(payload=(), time=0)]
    for (a, b) in readlines():
        max_accepted_time = (
            min(pos.time for pos in positions)
            + (18 - floor - a if floor > a
               else floor + a - 2 if floor < a
               else max(18 - floor - a, floor + a - 2))
        )
        positions = [
            possibility for possibility in chain.from_iterable(
                p.possibilities_to_take_next(floor, a, b) for p in positions
            ) if possibility.time <= max_accepted_time
        ]
        floor = a

    return min(p.time_to_get_free(floor) for p in positions) + 2 * n

print(main())


# python3
import sys
from collections import namedtuple

def readline(): return map(int, input().split())

def readlines():
    for line in sys.stdin.readlines():
        yield map(int, line.split())

class State(namedtuple('State', 'payload time floor')):
    def hook(self, pivot, a, b):
        assert pivot <= self.floor <= a or a <= self.floor <= pivot
        lo, up = min(pivot, a), max(pivot, a)
        return tuple(x for x in self.payload if x < lo or up < x) + (b,), \
            self.time + abs(self.floor - pivot) + abs(pivot - a)

    def choices_to_take_next(self, a, b):
        floor = self.floor

        payload, time = self.hook(floor, a, b)
        if len(payload) < 5:
            yield payload, time

        if floor > a:
            pivots = (x for x in self.payload if x > floor)
        elif floor == a:
            pivots = self.payload if len(self.payload) == 4 else ()
        else:
            pivots = (x for x in self.payload if x < floor)

        for pivot in pivots:
            yield self.hook(pivot, a, b)

def time_to_get_free(payload, floor):
    if payload:
        lo, up = min(payload), max(payload)
        return abs(lo-up) + min(abs(floor-lo), abs(floor-up))
    else:
        return 0

def main():
    n, = readline()

    floor = 1
    positions = {(): 0}  # empty elevator, time = 0
    for (a, b) in readlines():
        max_acceptable_time = min(positions.values()) + 16 - abs(floor - a)

        new_positions = dict()
        for payload, time in positions.items():
            state = State(payload, time, floor)
            for npayload, ntime in state.choices_to_take_next(a, b):
                if ntime <= max_acceptable_time:
                    npayload = tuple(sorted(npayload))
                    if new_positions.setdefault(npayload, ntime) > ntime:
                        new_positions[npayload] = ntime

        positions = new_positions
        floor = a

    return min(t + time_to_get_free(p, floor) for p, t in positions.items()) \
        + 2 * n

print(main())


# python3
import sys
from itertools import chain
from bisect import bisect_left as lower_bound, bisect_right as upper_bound, \
                   insort

def readline(): return map(int, input().split())

def readlines():
    for line in sys.stdin.readlines():
        yield map(int, line.split())

class Position(object):
    __slots__ = 'floor payload time'.split()

    def __init__(self, floor, payload, time):
        self.floor = floor
        self.payload = payload
        self.time = time

    def copy(self):
        return self.__class__(self.floor, list(self.payload), self.time)

    def is_not_full(self):
        return len(self.payload) < 4

    def take(self, b):
        insort(self.payload, b)
        return self

    def free(self, x, y):
        lo = lower_bound(self.payload, min(x, y))
        up = upper_bound(self.payload, max(x, y))
        del self.payload[lo:up]
        return self

    def hook(self, pivot, finish):
        self.time += abs(self.floor - pivot) + abs(pivot - finish)
        self.floor = finish
        self.free(*sorted([pivot, finish]))
        return self

    def possibilities_to_take_next(self, a, b):
        pivots = self.payload[upper_bound(self.payload, self.floor):] \
                 if a <= self.floor else \
                 self.payload[:lower_bound(self.payload, self.floor)]
        pivots.append(self.floor)

        for pivot in pivots:
            possibility = self.copy().hook(pivot, a)
            if possibility.is_not_full():
                yield possibility.take(b)

    def get_free(self):
        if self.payload:
            lo, up = self.payload[0], self.payload[-1]
            if self.floor <= (lo + up) // 2:
                self.hook(lo, up)
            else:
                self.hook(up, lo)
            assert not self.payload
        return self

#assert Position(floor=2, payload=[1, 2, 3, 3, 4, 5, 5, 6, 7], time=3)\
       #.free(3, 5) == Position(floor=2, payload=[1, 2, 6, 7], time=3)

#assert Position(floor=4, payload=[1, 2, 3, 3, 4, 5, 5, 6, 7], time=3)\
       #.hook(2, 6) == Position(floor=6, payload=[1, 7], time=9)

#assert Position(floor=4, payload=[1, 5], time=0)\
       #.take(9) == Position(floor=4, payload=[1, 5, 9], time=0)

#assert list(Position(floor=4, payload=[1, 2, 5], time=0)
            #.possibilities_to_take_next(2, 9))\
       #== [Position(floor=2, payload=[1, 9], time=4),
           #Position(floor=2, payload=[1, 5, 9], time=2)]

#assert list(Position(floor=4, payload=[1, 2, 5], time=0)
            #.possibilities_to_take_next(5, 1)) \
       #== [Position(floor=5, payload=[1], time=7),
           #Position(floor=5, payload=[1, 1], time=5),
           #Position(floor=5, payload=[1, 1, 2], time=1)]

def main():
    n, = readline()

    positions = [Position(floor=1, payload=[], time=0)]
    for (a, b) in readlines():
        positions = list(chain.from_iterable(p.possibilities_to_take_next(a, b)
                                             for p in positions))

    return min(pos.get_free().time for pos in positions) + 2 * n

print(main())


# python3
import sys
from itertools import chain
from collections import namedtuple

def readline(): return map(int, input().split())

def readlines():
    for line in sys.stdin.readlines():
        yield map(int, line.split())

class Position(namedtuple('Position', 'payload time')):
    # def __eq__(self, other):
    #     return self.time == other.time \
    #            and sorted(self.payload) == sorted(other.payload)

    def is_not_full(self):
        return len(self.payload) < 4

    def take(self, b):
        self.payload.append(b)
        return self

    def free(self, x, y):
        x, y = sorted((x, y))
        return [s for s in self.payload if not x <= s <= y]

    def hook(self, start, pivot, finish):
        time = self.time + abs(start - pivot) + abs(pivot - finish)
        return Position(self.free(pivot, finish), time)

    def possibilities_to_take_next(self, floor, a, b):
        pivots = [x for x in self.payload if x > floor] \
                 if a < floor else \
                 [x for x in self.payload if x < floor] \
                 if a > floor else \
                 [] if self.is_not_full() else list(self.payload)
        pivots.append(floor)

        for pivot in pivots:
            possibility = self.hook(floor, pivot, a)
            if possibility.is_not_full():
                yield possibility.take(b)

    def time_to_get_free(self, floor):
        if self.payload:
            lo, up = min(self.payload), max(self.payload)
            return self.time + abs(lo-up) + min(abs(floor-lo), abs(floor-up))
        else:
            return self.time

# assert sorted(Position(payload=[1, 2, 3, 3, 4, 5, 5, 6, 7], time=3)
#               .free(3, 5)) == [1, 2, 6, 7]

# assert Position(payload=[1, 2, 3, 3, 4, 5, 5, 6, 7], time=3)\
#        .hook(4, 2, 6) == Position(payload=[1, 7], time=9)

# assert Position(payload=[1, 5], time=0)\
#        .take(9) == Position(payload=[1, 5, 9], time=0)

# assert list(Position(payload=[1, 2, 5], time=0)
#             .possibilities_to_take_next(4, 2, 9))\
#        == [Position(payload=[1, 9], time=4),
#            Position(payload=[1, 5, 9], time=2)]

# assert list(Position(payload=[1, 2, 5], time=0)
#             .possibilities_to_take_next(4, 5, 1)) \
#        == [Position(payload=[1], time=7),
#            Position(payload=[1, 1], time=5),
#            Position(payload=[1, 1, 2], time=1)]

def main():
    n, = readline()

    floor = 1
    positions = [Position(payload=[], time=0)]
    for (a, b) in readlines():
        max_accepted_time = (
            min(pos.time for pos in positions)
            + (18 - floor - a if floor > a
               else floor + a - 2 if floor < a
               else max(18 - floor - a, floor + a - 2))
        )
        positions = [
            p for p in chain.from_iterable(
                p.possibilities_to_take_next(floor, a, b) for p in positions
            ) if p.time <= max_accepted_time
        ]
        floor = a

    return min(pos.time_to_get_free(floor) for pos in positions) + 2 * n

print(main())


# python3
import sys
from itertools import chain
from collections import namedtuple

def readline(): return map(int, input().split())

def readlines():
    for line in sys.stdin.readlines():
        yield map(int, line.split())

class Position(namedtuple('Position', 'payload time')):
    # def __eq__(self, other):
    #     return self.time == other.time \
    #            and sorted(self.payload) == sorted(other.payload)

    def hook(self, floor, pivot, a, b):
        lo, up = min(pivot, a), max(pivot, a)
        return Position(tuple(x for x in self.payload if x < lo or up < x)
                        + (b,),
                        self.time + abs(floor - pivot) + abs(pivot - a))

    def possibilities_to_take_next(self, floor, a, b):
        shortest = self.hook(floor, floor, a, b)
        if len(shortest.payload) < 5:
            yield shortest

        if floor > a:
            pivots = (x for x in self.payload if x > floor)
        elif floor == a:
            pivots = self.payload if len(self.payload) == 4 else ()
        else:
            pivots = (x for x in self.payload if x < floor)

        for pivot in pivots:
            possibility = self.hook(floor, pivot, a, b)
            yield possibility

    def time_to_get_free(self, floor):
        if self.payload:
            lo, up = min(self.payload), max(self.payload)
            return self.time + abs(lo-up) + min(abs(floor-lo), abs(floor-up))
        else:
            return self.time

def main():
    n, = readline()

    floor = 1
    positions = [Position(payload=(), time=0)]
    for (a, b) in readlines():
        max_acceptable_time = min(pos.time for pos in positions) \
                              + 16 - abs(floor - a)
        positions = [
            possibility for possibility in chain.from_iterable(
                p.possibilities_to_take_next(floor, a, b) for p in positions
            ) if possibility.time <= max_acceptable_time
        ]
        floor = a

    return min(p.time_to_get_free(floor) for p in positions) + 2 * n

print(main())


# python3
import sys
from itertools import chain
from collections import namedtuple

def readline(): return map(int, input().split())

def readlines():
    for line in sys.stdin.readlines():
        yield map(int, line.split())

class Position(namedtuple('Position', 'payload time')):
    # def __eq__(self, other):
    #     return self.time == other.time \
    #            and sorted(self.payload) == sorted(other.payload)

    def hook(self, start, pivot, a, b):
        lo, up = min(pivot, a), max(pivot, a)
        return Position(tuple(x for x in self.payload if not lo <= x <= up)
                        + (b,),
                        self.time + abs(start - pivot) + abs(pivot - a))

    def possibilities_to_take_next(self, floor, a, b):
        shortest = self.hook(floor, floor, a, b)
        if len(shortest.payload) < 5:
            yield shortest

        if floor > a:
            pivots = (x for x in self.payload if x > floor)
        elif floor == a:
            pivots = self.payload
        else:
            pivots = (x for x in self.payload if x < floor)

        for pivot in pivots:
            possibility = self.hook(floor, pivot, a, b)
            yield possibility

    def time_to_get_free(self, floor):
        if self.payload:
            lo, up = min(self.payload), max(self.payload)
            return self.time + abs(lo-up) + min(abs(floor-lo), abs(floor-up))
        else:
            return self.time

def main():
    n, = readline()

    floor = 1
    positions = [Position(payload=(), time=0)]
    for (a, b) in readlines():
        max_acceptable_time = min(pos.time for pos in positions) + 16
        positions = [
            possibility for possibility in chain.from_iterable(
                p.possibilities_to_take_next(floor, a, b) for p in positions
            ) if possibility.time < max_acceptable_time
        ]
        floor = a

    return min(p.time_to_get_free(floor) for p in positions) + 2 * n

print(main())


# python3
import sys
from itertools import chain
from collections import namedtuple

def readline(): return map(int, input().split())

def readlines():
    for line in sys.stdin.readlines():
        yield map(int, line.split())

class Position(namedtuple('Position', 'payload time')):
    # def __eq__(self, other):
    #     return self.time == other.time \
    #            and sorted(self.payload) == sorted(other.payload)

    def free(self, x, y):
        x, y = sorted((x, y))
        return tuple(s for s in self.payload if not x <= s <= y)

    def hook(self, start, pivot, finish, b):
        time = self.time + abs(start - pivot) + abs(pivot - finish)
        return Position(self.free(pivot, finish) + (b,), time)

    def possibilities_to_take_next(self, floor, a, b):
        if a == floor:
            pivots = [] if len(self.payload) < 4 else tuple(self.payload)
        else:
            pivots = [x for x in self.payload if x > floor] \
                     if a < floor else \
                     [x for x in self.payload if x < floor]
        pivots.append(floor)

        for pivot in pivots:
            possibility = self.hook(floor, pivot, a, b)
            if len(possibility.payload) < 5:
                yield possibility

    def time_to_get_free(self, floor):
        if self.payload:
            lo, up = min(self.payload), max(self.payload)
            return self.time + abs(lo-up) + min(abs(floor-lo), abs(floor-up))
        else:
            return self.time

# assert sorted(Position(payload=[1, 2, 3, 3, 4, 5, 5, 6, 7], time=3)
#               .free(3, 5)) == [1, 2, 6, 7]

# assert Position(payload=[1, 2, 3, 3, 4, 5, 5, 6, 7], time=3)\
#        .hook(4, 2, 6, 777) == Position(payload=[1, 7, 777], time=9)

# assert list(Position(payload=[1, 2, 5], time=0)
#             .possibilities_to_take_next(4, 2, 9))\
#        == [Position(payload=[1, 9], time=4),
#            Position(payload=[1, 5, 9], time=2)]

# assert list(Position(payload=[1, 2, 5], time=0)
#             .possibilities_to_take_next(4, 5, 1)) \
#        == [Position(payload=[1], time=7),
#            Position(payload=[1, 1], time=5),
#            Position(payload=[1, 1, 2], time=1)]

def main():
    n, = readline()

    floor = 1
    positions = [Position(payload=(), time=0)]
    for (a, b) in readlines():
        max_accepted_time = (
            min(pos.time for pos in positions)
            + (18 - floor - a if floor > a
               else floor + a - 2 if floor < a
               else max(18 - floor - a, floor + a - 2))
        )
        positions = [
            possibility for possibility in chain.from_iterable(
                p.possibilities_to_take_next(floor, a, b) for p in positions
            ) if possibility.time <= max_accepted_time
        ]
        floor = a

    return min(p.time_to_get_free(floor) for p in positions) + 2 * n

print(main())


import java.util.*

// Reads multiple ints in a line, separate by a space.
// It works even if the actual number of ints is smaller than n.
// WARNING: This function does not work for -2^31.
// NOTE: This function does not handle error cases.
fun fastReadInts(n: Int): IntArray {
  val xs = IntArray(n)
  val s = readLine()!!
  var currentValue = 0
  var isNegative = false
  var currentIndex = 0
  for (c in s) {
    if (c == ' ') {
      xs[currentIndex] = currentValue * if (isNegative) -1 else 1
      currentValue = 0
      isNegative = false
      currentIndex++
    } else if (c == '-') {
      isNegative = true
    } else {
      currentValue *= 10
      currentValue += c - '0'
    }
  }
  xs[currentIndex] = currentValue * if (isNegative) -1 else 1
  return xs
}

data class Person(val s: Int  /* source */, val d: Int  /* destination */)

data class Vertex(val completed: Int, val floor: Int, val ds: List<Int>)

data class State(val vertex: Vertex, val cost: Int)

fun main(args: Array<String>) {
  val n = readLine()!!.toInt()
  val persons = Array(n, {
    val (s, d) = fastReadInts(2)
    Person(s, d)
  })

  val initialState = State(Vertex(0, 1, listOf()), 0)
  val visited = mutableSetOf<Vertex>()
  val pq = PriorityQueue<State>(compareBy { it.cost })
  pq.add(initialState)
  while (pq.isNotEmpty()) {
    val state = pq.poll()
    // println(state)
    if (state.vertex.completed == n) {
      println(state.cost)
      return
    }

    val vertex = state.vertex
    if (visited.contains(vertex)) continue

    visited.add(vertex)

    val floor = vertex.floor
    val ds = vertex.ds
    // Get off
    if (ds.contains(floor)) {
      val count = ds.count { it == floor }
      val nextDs = ds.toMutableList()
      nextDs.removeAll { it == floor }
      val nextVertex = Vertex(vertex.completed + count, floor, nextDs)
      val nextState = State(nextVertex, state.cost + count)
      pq.add(nextState)
      continue
    }

    // Get on
    val nextPersonId = vertex.completed + ds.size
    if (nextPersonId < n && persons[nextPersonId].s == floor && ds.size < 4) {
      val nextDs = ds.toMutableList()
      nextDs.add(persons[nextPersonId].d)
      nextDs.sort()
      val nextVertex = Vertex(vertex.completed, floor, nextDs)
      val nextState = State(nextVertex, state.cost + 1)
      pq.add(nextState)
      continue
    }

    // Move
    // Move 1: Next person floor
    if (nextPersonId < n && ds.size < 4) {
      val nextFloor = persons[nextPersonId].s
      val nextVertex = Vertex(vertex.completed, nextFloor, ds)
      val nextState = State(nextVertex, state.cost + Math.abs(nextFloor - floor))
      pq.add(nextState)
    }
    // Move 2: Get off floors.
    for (d in ds) {
      val nextFloor = d
      val nextVertex = Vertex(vertex.completed, nextFloor, ds)
      val nextState = State(nextVertex, state.cost + Math.abs(nextFloor - floor))
      pq.add(nextState)
    }
  }
}


import java.io.*;
import java.util.*;
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskE solver = new TaskE();
        solver.solve(1, in, out);
        out.flush();out.close();
    }
        static class TaskE {
          int n,max=Integer.MAX_VALUE;
          int a[][];
          HashMap<Integer,Integer> hm[][];
          int[] get(int no){
           int x[]=new int[4];
           int p=0;
           while(no!=0){
            x[p++]=no%10;no/=10;
           }Arrays.sort(x);
           return x;
          }
          int get(int[] x){
           int ans=0,m=1;
           for(int i=0;i<4;i++){
            ans+=x[i]*m;m*=10;
           }return ans;
          }
          int[] m(int no,int v){
           int a[]=get(no);boolean is=false;
           for(int i=0;i<4;i++){
            if(a[i]==0){
             is=true;a[i]=v;break;
            }
           }
           if(!is)return null;
           Arrays.sort(a);
           return a;
          }
          int rec(int id,int pe,int x[]){
           if(x==null)return max/2;
           int no=get(x),min=max;
           if(hm[id][pe].containsKey(no))return hm[id][pe].get(no);
           if(pe==n){
            int v1=0,pr=id;
            for(int i=0;i<4;i++){
             if(x[i]==0)continue;
             v1+=Math.abs(x[i]-pr)+1;pr=x[i];
            }
            int v2=0;pr=id;
            for(int i=3;i>=0;i--){
             if(x[i]==0)continue;
             v2+=Math.abs(x[i]-pr)+1;pr=x[i];
            }
//            System.out.println(v1+" "+v2);
            hm[id][pe].put(no,Math.min(v1,v2));
            return hm[id][pe].get(no);
           }
           int v[]=new int[4],p;
           for(int i=0;i<(1<<4);i++){
            v[0]=v[1]=v[2]=v[3]=0;p=0;
            int got=no,m=1;
            for(int j=0;j<4;j++){
             if(((i>>j)&1)!=0){
              v[p++]=x[j];got-=x[j]*m;
             }m*=10;
            }
            if(a[pe+1][0]>=id){
             int pr=id,val=0;
             for(int z=0;z<p;z++){
              if(v[z]==0)continue;
              val+=Math.abs(v[z]-pr)+1;pr=v[z];
             }
             val+=Math.abs(a[pe+1][0]-pr)+1;
//             System.out.println(val+" "+got);
             min=Math.min(min,rec(a[pe+1][0],pe+1,m(got,a[pe+1][1]))+val);
            }else{
             int pr=id,val=0;
             for(int z=p-1;z>=0;z--){
              if(v[z]==0)continue;
              val+=Math.abs(v[z]-pr)+1;pr=v[z];
             }
             val+=Math.abs(a[pe+1][0]-pr)+1;
             min=Math.min(min,rec(a[pe+1][0],pe+1,m(got,a[pe+1][1]))+val);
            }
           }
           hm[id][pe].put(no,min);
           return hm[id][pe].get(no);
          }
          public void solve(int testNumber, InputReader in, PrintWriter out) {
              n=in.nextInt();
              a=new int[n+1][n+1];
              for(int i=1;i<=n;i++){
               a[i][0]=in.nextInt();a[i][1]=in.nextInt();
              }
              hm=new HashMap[10][n+1];
              for(int i=0;i<10;i++){
               for(int j=0;j<=n;j++)hm[i][j]=new HashMap<>();
              }
              out.print(rec(1,0,get(0)));
          }
          //          int ja[][],from[],to[],c[];
    //              void make(int n,int m,InputReader in){
    //               ja=new int[n+1][];from=new int[m];to=new int[m];c=new int[n+1];
    //               for(int i=0;i<m;i++){
    //                from[i]=in.nextInt();to[i]=in.nextInt();
    //                c[from[i]]++;c[to[i]]++;
    //               }
    //               for(int i=1;i<=n;i++){
    //                ja[i]=new int[c[i]];c[i]=0;
    //               }
    //               for(int i=0;i<m;i++){
    //                ja[from[i]][c[from[i]]++]=to[i];
    //                ja[to[i]][c[to[i]]++]=from[i];
    //               }
    //              }
//            int[] radixSort(int[] f){ return radixSort(f, f.length); }
//    	int[] radixSort(int[] f, int n)
//    	{
//    		int[] to = new int[n];
//    		{
//    			int[] b = new int[65537];
//    			for(int i = 0;i < n;i++)b[1+(f[i]&0xffff)]++;
//    			for(int i = 1;i <= 65536;i++)b[i]+=b[i-1];
//    			for(int i = 0;i < n;i++){
//                             to[b[f[i]&0xffff]++] = f[i];
//                            }
//    			int[] d = f; f = to;to = d;
//    		}
//    		{
//    			int[] b = new int[65537];
//    			for(int i = 0;i < n;i++)b[1+(f[i]>>>16)]++;
//    			for(int i = 1;i <= 65536;i++)b[i]+=b[i-1];
//    			for(int i = 0;i < n;i++)to[b[f[i]>>>16]++] = f[i];
//    			int[] d = f; f = to;to = d;
//    		}
//    		return f;
//    	}

       }
    static class InputReader {
        BufferedReader br;
        StringTokenizer st;
        public InputReader(InputStream stream) {
            br = new BufferedReader(new InputStreamReader(stream));
            st = null;
        }

        String next() {
            while (st == null || !st.hasMoreTokens()) {
                String s = null;
                try {
                    s = br.readLine();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (s == null)
                    return null;
                st = new StringTokenizer(s);
            }
            return st.nextToken();
        }

        boolean hasMoreTokens() {
            while (st == null || !st.hasMoreTokens()) {
                String s = null;
                try {
                    s = br.readLine();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (s == null)
                    return false;
                st = new StringTokenizer(s);
            }
            return true;
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }
        public long nextLong() {
            return Long.parseLong(next());
        }
        public double nextDouble() {
            return Double.parseDouble(next());
        }
    }
}