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: Time Limit Exceeded)

using System;

class Program
{
    static void Main(string[] args)
    {
        string a = Console.ReadLine();
        string b = Console.ReadLine();
        string c = Console.ReadLine();
     
        int minLength = a.Length + b.Length + c.Length;

        for (int i = -b.Length - c.Length; i <= a.Length + c.Length; i++)
        {
            int l = GetMergedLength(a, b, i);
            if (l > minLength)
                continue;
            string ab = MergeTwo(a, b, i, l);
            if (ab == null)
                continue;
            for (int j = -c.Length; j <= ab.Length; j++)
            {
                l = GetMergedLength(ab, c, j);
                if (l > minLength)
                    continue;
                string abc = MergeTwo(ab, c, j, l);
                if (abc != null && abc.Length < minLength)
                {
                    minLength = abc.Length;
                }
            }
        }
        Console.WriteLine(minLength);
    }

    static string MergeTwo(string a, string b, int offset, int l)
    {
        if (offset < 0)
            return MergeTwo(b, a, -offset, l);
        else if (offset == a.Length)
            return a + b;
        else if (offset > a.Length)
            return a + new string('?', offset - a.Length) + b;

        var merged = new char[l];
        for (int i = 0; i < a.Length; i++)
            merged[i] = a[i];

        for (int i = 0; i < Math.Min(a.Length - offset, b.Length); i++)
        {
            int j = i + offset;
            if (a[j] == '?')
                merged[j] = b[i];
            else if (b[i] == '?' || a[j] == b[i])
                merged[j] = a[j];
            else
                return null;
        }
        for (int i = a.Length, j = a.Length - offset; i < merged.Length; i++, j++)
            merged[i] = b[j];
        return new string(merged);
    }

    static int GetMergedLength(string a, string b, int offset)
    {
        if (offset < 0)
            return GetMergedLength(b, a, -offset);
        int l = offset + b.Length;
        if (l < a.Length)
            return a.Length;
        return l;
    }
}