#pragma GCC optimize("O3", "unroll-loops")
#pragma GCC target("avx2")

#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <bitset>
#include <sstream>
#include <deque>
#include <queue>
#include <complex>
#include <random>
#include <cassert>
#include <chrono>

using namespace std;

#define FAST ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define FIXED cout << fixed << setprecision(12)
#define ll long long
#define ld long double
#define pii pair<int, int>
#define pll pair<ll, ll>
#define graph vector<vector<int>>
#define pb push_back
#define pf push_front
#define popb pop_back
#define popf pop_front
#define f first
#define s second
#define hashmap unordered_map
#define hashset unordered_set
#define eps 1e-9
#define mod 1000000007
#define inf 3000000000000000007ll
#define sz(a) signed(a.size())
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()

#ifdef DEBUG
    mt19937 gen(857204);
#else
    mt19937 gen(chrono::high_resolution_clock::now().time_since_epoch().count());
#endif

template<class T, class U> inline void checkmin(T &x, U y) { if (y < x) x = y; }
template<class T, class U> inline void checkmax(T &x, U y) { if (y > x) x = y; }
template<class T, class U> inline bool ifmax(T &x, U y) { if (y > x) return x = y, true; return false; }
template<class T, class U> inline bool ifmin(T &x, U y) { if (y < x) return x = y, true; return false; }
template<class T> inline void sort(T &a) { sort(all(a)); }
template<class T> inline void rsort(T &a) { sort(rall(a)); }
template<class T> inline void reverse(T &a) { reverse(all(a)); }
template<class T, class U> inline istream& operator>>(istream& str, pair<T, U> &p) { return str >> p.f >> p.s; }
template<class T> inline istream& operator>>(istream& str, vector<T> &a) { for (auto &i : a) str >> i; return str; }
template<class T> inline T sorted(T a) { sort(a); return a; }

vector<int> start(string a, string b) {
    vector<int> ans;
    for (int i = 0; i < sz(a); ++i) {
        bool flag = true;
        for (int j = 0; j < sz(b) && i + j < sz(a); ++j) {
            if (a[i + j] != '?' && b[j] != '?' && a[i + j] != b[j])
                flag = false;
        }
        if (flag) ans.pb(i);
    }
    ans.pb(sz(a));
    return ans;
}

int solve(string a, string b, string c) {
    vector<int> sab = start(a, b), sac = start(a, c), sbc = start(b, c);
    hashset<int> stbc(all(sbc));
    int ans = mod;
    for (auto i : sab)
        for (auto j : sac)
            if (j >= i) {
                if (stbc.count(j - i) || j - i >= sz(b))
                    checkmin(ans, max(sz(a), max(i + sz(b), j + sz(c))));
            }
    for (auto i : sab)
        for (auto j : sbc)
            if (i + j >= sz(a))
                checkmin(ans, max(i + sz(b), i + j + sz(c)));
    return ans;
}

signed main() {
    FAST; FIXED;
    string a, b, c;
    cin >> a >> b >> c;
    int ans = mod;
    checkmin(ans, solve(a, b, c));
    checkmin(ans, solve(a, c, b));
    checkmin(ans, solve(b, a, c));
    checkmin(ans, solve(b, c, a));
    checkmin(ans, solve(c, a, b));
    checkmin(ans, solve(c, b, a));
    cout << ans;
    #ifdef DEBUG
        cerr << "Runtime is: " << clock() * 1.0 / CLOCKS_PER_SEC << endl;
    #endif
    return 0;
}

Measured memory_bytes: 384