#![allow(bare_trait_objects)]
#![allow(unused_imports)]
#![allow(dead_code)]

use std::fmt::Debug;
use std::io::BufRead;
use std::io::Stdin;
use std::io::StdinLock;
use std::str::FromStr;

pub struct Scanner<'a> {
    // stdin: Stdin,
    buf_read: Box<BufRead + 'a>,
    tokens: Vec<String>,
}

impl<'a> Scanner<'a> {
    pub fn new(buf_read: StdinLock<'a>) -> Self {
        Scanner {
            buf_read: Box::new(buf_read),
            tokens: Vec::new(),
        }
    }

    // pub fn from_stdin() -> Self {
    //     let stdin = Box::leak(Box::new(std::io::stdin()));
    //     Self {
    //         buf_read: Box::new(stdin.lock()),
    //         tokens: Vec::new(),
    //     }
    // }

    pub fn next(&mut self) -> String {
        while self.tokens.is_empty() {
            let mut s = String::new();
            if self.buf_read.read_line(&mut s).is_err() {
                panic!()
            }
            self.tokens = s
                .split_whitespace()
                .filter(|s| !s.is_empty())
                .rev()
                .map(str::to_string)
                .collect();
        }
        self.tokens.pop().unwrap()
    }

    pub fn next_g<T: FromStr>(&mut self) -> T
    where
        T::Err: Debug,
    {
        self.next().parse().unwrap()
    }

    pub fn next_vec_g<T: FromStr>(&mut self, n: usize) -> Vec<T>
    where
        T::Err: Debug,
    {
        (0..n).map(|_| self.next_g()).collect()
    }

    pub fn usize(&mut self) -> usize {
        self.next_g()
    }

    pub fn i64(&mut self) -> i64 {
        self.next_g()
    }

    pub fn vec_i64(&mut self, n: usize) -> Vec<i64> {
        self.next_vec_g(n)
    }
}

fn iota(n: usize) -> Vec<usize> {
    let mut ps = Vec::with_capacity(n);
    for i in 0..n {
        ps.push(i);
    }
    ps
}

struct Permutation {
    n: usize,
    ps: Vec<usize>,
}

impl Iterator for Permutation {
    type Item = Vec<usize>;

    fn next(&mut self) -> Option<Vec<usize>> {
        if self.n == 0 {
            return None;
        }

        if self.ps.len() != self.n {
            self.ps = iota(self.n);
        } else {
            let mut i = self.n - 1;
            while i > 0 && self.ps[i - 1] > self.ps[i] {
                i -= 1;
            }
            if i == 0 {
                return None;
            }
            for j in 0..(self.n - i) / 2 {
                self.ps.swap(i + j, self.n - 1 - j);
            }
            for j in i.. {
                if self.ps[i - 1] < self.ps[j] {
                    self.ps.swap(i - 1, j);
                    break;
                }
            }
        }

        Some(self.ps.clone())
    }
}

fn permutation(n: usize) -> Permutation {
    Permutation {
        n: n,
        ps: Vec::new(),
    }
}

fn main() {
    let stdin = std::io::stdin();
    let mut sc = Scanner::new(stdin.lock());

    let a = sc.next();
    let b = sc.next();
    let c = sc.next();

    // for ps in permutation(3) {
    //     eprintln!("{:?}", ps);
    // }

    let mut ans = 10000000;
    let ss = &[a, b, c];
    for ps in permutation(3) {
        let i = ps[0];
        let j = ps[1];
        let k = ps[2];

        let a = &ss[i].chars().collect::<Vec<_>>();
        let b = &ss[j].chars().collect::<Vec<_>>();
        let c = &ss[k].chars().collect::<Vec<_>>();

        let f = |a: &[char], b: &[char]| -> Vec<bool> {
            let mut okij = vec![true; 6001];
            for i in 0..a.len() {
                okij[i] = (0..b.len())
                    .take(a.len() - i)
                    .all(|j| a[i + j] == b[j] || a[i + j] == '?' || b[j] == '?');
            }
            okij
        };

        let okij = f(a, b);
        let okik = f(a, c);
        let okjk = f(b, c);

        // eprintln!("{:?}", &okij[0..10]);
        // eprintln!("{:?}", &okik[0..10]);
        // eprintln!("{:?}", &okjk[0..10]);

        for i in 0..a.len() + 1 {
            for j in 0..std::cmp::max(a.len() - i, b.len()) + 1 {
                if okij[i] && okik[i + j] && okjk[j] {
                    ans = std::cmp::min(
                        ans,
                        *[a.len(), i + b.len(), i + j + c.len()]
                            .iter()
                            .max()
                            .unwrap(),
                    );
                }
            }
        }
    }

    println!("{}", ans);
}


Measured memory_bytes: 4352