Problem:
Score : 500 points

Problem Statement

Snuke has a string s.
From this string, Anuke, Bnuke, and Cnuke obtained strings a, b, and c, respectively, as follows:

Choose a non-empty (contiguous) substring of s (possibly s itself). Then, replace some characters (possibly all or none) in it with ?s.

For example, if s is mississippi, we can choose the substring ssissip and replace its 1-st and 3-rd characters with ? to obtain ?s?ssip.

You are given the strings a, b, and c.
Find the minimum possible length of s.

Constraints

1 \leq |a|, |b|, |c| \leq 2000

a, b, and c consists of lowercase English letters and ?s.

Input

Input is given from Standard Input in the following format:

a
b
c

Output

Print the minimum possible length of s.

Sample Input 1

a?c
der
cod

Sample Output 1

7

For example, s could be atcoder.

Sample Input 2

atcoder
atcoder
???????

Sample Output 2

7

a, b, and c may not be distinct.

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;

public class Solve
{
    static void Main(string[] args)
    {
        new ABC_E();
    }
}

public class ABC_E
{
    string[] s = new string[3];
    string[] abc = new string[3];
    int[] p = new int[] { 0, 1, 2 };

    const int MX = 2005;
    /// <summary>
    /// [1文字目index, 2文字目index, ずれ幅]
    /// </summary>
    bool[,,] d = new bool[3, 3, MX];

    int ans = MX * 3;

    public ABC_E()
    {
        In();

        do
        {
            s[0] = abc[p[0]];
            s[1] = abc[p[1]];
            s[2] = abc[p[2]];

            Slide(0, 1);
            Slide(1, 2);
            Slide(0, 2);

            for (int x = 0; x < MX; x++)
                for (int y = 0; y < MX; y++)
                {
                    if (!f(0, 1, x)) continue;
                    if (!f(1, 2, y)) continue;
                    if (!f(0, 2, x + y)) continue;
                    int now = 0;
                    now = Math.Max(now, s[0].Length);
                    now = Math.Max(now, x + s[1].Length);
                    now = Math.Max(now, x + y + s[2].Length);
                    ans = Math.Min(ans, now);
                }

        } while (NextPermutation(p));

        Console.WriteLine(ans);
    }

    bool f(int i, int j, int k)
    {
        if (k >= s[i].Length) return true;
        return d[i, j, k];
    }

    void Slide(int i, int j)
    {
        for (int k = 0; k < s[i].Length; k++)
        {
            d[i, j, k] = Check(i, j, k);
        }
    }

    /// <summary>
    /// 同じ位置に同じ文字があるか
    /// </summary>
    bool Check(int i, int j, int k)
    {
        for (int ni = k; ni < s[i].Length; ni++)
        {
            int nj = ni - k;
            if (nj >= s[j].Length) break;
            if (s[i][ni] == '?' || s[j][nj] == '?') continue;
            if (s[i][ni] != s[j][nj]) return false;
        }
        return true;
    }

    void In()
    {
        abc[0] = Console.ReadLine().Trim();
        abc[1] = Console.ReadLine().Trim();
        abc[2] = Console.ReadLine().Trim();
    }

    void swap(int[] nums, int i, int j)
    {
        var tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }

    void reverse(int[] nums, int start)
    {
        int i = start;
        int j = nums.Length - 1;
        while (i < j)
        {
            swap(nums, i, j);
            i++;
            j--;
        }
    }

    bool NextPermutation(int[] nums)
    {
        int i = nums.Length - 2;
        while (i >= 0 && nums[i + 1] < nums[i])
        {
            i--;
        }
        if (i >= 0)
        {
            int j = nums.Length - 1;
            while (j >= 0 && nums[j] <= nums[i])
            {
                j--;
            }
            swap(nums, i, j);
        }
        reverse(nums, i + 1);
        return (i >= 0);
    }
}

public class ABC_F
{
    public ABC_F()
    {

    }
}