package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

func main() {
	sc := newInputScanner(true, 1024)
	a, b, c := sc.nextStr(), sc.nextStr(), sc.nextStr()
	ab, ac, bc := newMatchTable(a, b), newMatchTable(a, c), newMatchTable(b, c)
	aLength, bLength, cLength := len(a), len(b), len(c)
	start := -(bLength + cLength)
	answer := aLength + bLength + cLength
	var left, bEnd, cEnd, right, curLength int
	for i := start; i <= aLength+cLength; i++ {
		for j := start; j <= aLength+bLength; j++ {
			if ab.couldMatch(i) && ac.couldMatch(j) && bc.couldMatch(j-i) {
				if i >= 0 && j >= 0 {
					left = 0
				} else if i > j {
					left = j
				} else {
					left = i
				}
				bEnd = i + bLength
				cEnd = j + cLength
				if bEnd > cEnd {
					right = bEnd
				} else {
					right = cEnd
				}
				if aLength > right {
					right = aLength
				}
				if curLength = right - left; curLength < answer {
					answer = curLength
				}
			}
		}
	}
	fmt.Println(answer)
}

type matchTable struct {
	debuggable
	targetLength int
	offset       int
	matched      []bool
}

func newMatchTable(target string, match string) *matchTable {
	targetLength := len(target)
	offset := len(match)
	matched := make([]bool, targetLength+offset-1)
	t := &matchTable{
		targetLength: targetLength,
		offset:       offset,
		matched:      matched,
	}
	t.process(target, match)
	t.debugPrint()
	return t
}

func (t *matchTable) process(target string, match string) {
	t.debug(func() {
		fmt.Println("processing ", target, match)
	})
	var tIndex, mIndex int
	var tByte, mByte byte
	for i := -t.offset + 1; i < t.targetLength; i++ {
		if i < 0 {
			tIndex = 0
			mIndex = -i
		} else {
			tIndex = i
			mIndex = 0
		}
		isMatched := true
		for tIndex < t.targetLength && mIndex < t.offset {
			tByte = target[tIndex]
			mByte = match[mIndex]
			t.debug(func() {
				fmt.Println("checking ", string(tByte), string(mByte))
			})
			if tByte != '?' && mByte != '?' && tByte != mByte {
				isMatched = false
				break
			}
			tIndex++
			mIndex++
		}
		t.matched[i+t.offset-1] = isMatched
	}
}

// i: (-offset, targetLength)
func (t *matchTable) couldMatch(i int) bool {
	if i+t.offset <= 0 || i >= t.targetLength {
		return true
	}
	return t.matched[i+t.offset-1]
}

func (t *matchTable) debugPrint() {
	t.debug(func() {
		fmt.Println(t.matched)
		fmt.Println("------------")
	})
}

type inputScanner struct {
	*bufio.Scanner
}

func newInputScanner(enabledScanWords bool, sizeInKB int) *inputScanner {
	scanner := bufio.NewScanner(os.Stdin)
	if enabledScanWords {
		scanner.Split(bufio.ScanWords)
	}
	capacity := sizeInKB * 1024
	buf := make([]byte, capacity)
	scanner.Buffer(buf, capacity)
	return &inputScanner{
		Scanner: scanner,
	}
}

func (inputSc *inputScanner) nextInt() int {
	i, e := strconv.Atoi(inputSc.nextStr())
	if e != nil {
		panic(e)
	}
	return i
}

func (inputSc *inputScanner) nextUInt64() uint64 {
	i, e := strconv.ParseUint(inputSc.nextStr(), 10, 64)
	if e != nil {
		panic(e)
	}
	return i
}

func (inputSc *inputScanner) nextStr() string {
	inputSc.Scan()
	return inputSc.Text()
}

type debuggable struct {
}

const (
	DEBUG_ON = false
)

func (d *debuggable) debug(f func()) {
	if DEBUG_ON {
		f()
	}
}


Measured memory_bytes: 768