unittest
{
	assert( [ "a?c", "der", "cod" ].parse.expand.solve == 7 );
	assert( [ "atcoder", "atcoder", "???????" ].parse.expand.solve == 7 );
	
	assert( [ "?".repeat( 2000 ).join( "" ), "?".repeat( 2000 ).join( "" ), "?".repeat( 2000 ).join( "" ) ].parse.expand.solve == 2000 );		// 追加ケース
}



import std.algorithm;
import std.conv;
import std.range;
import std.stdio;
import std.typecons;

void main()
{
	stdin.byLineCopy.parse.expand.solve.writeln;
}

auto parse( Range )( Range input )
if( isInputRange!Range && is( ElementType!Range == string ) )
{
	auto abc = new dchar[][ 3 ];
	foreach( ref x; abc )
	{
		x = input.front.to!( dchar[] );
		input.popFront;
	}
	return tuple( abc );
}

auto solve( dchar[][] abc )
{
	auto ans = long.max;
	foreach( ps; iota( 3 ).permutations )
	{
		auto s = solve2( solve2( abc[ ps[ 0 ] ], abc[ ps[ 1 ] ] ), abc[ ps[ 2 ] ] );
		ans = min( ans, s.length );
	}
	return ans;
}

auto solve2( dchar[] xs, dchar[] ys )
{
	LOOP: foreach( i; 0L .. xs.length.signed )
	{
		auto xxs = xs[ i .. min( $, i + ys.length ) ];
		auto yys = ys[ 0 .. xxs.length ];
		foreach( j, x, y; lockstep( xxs, yys ) )
		{
			if( x != '?' && y != '?' && x != y ) continue LOOP;
		}
		auto xys = new dchar[ xxs.length ];
		foreach( ref xy, x, y; lockstep( xys, xxs, yys ) )
		{
			xy = ( x != '?' ) ? x : y;
		}
		return xs[ 0 .. $ - xys.length ] ~ xys ~ ys[ xys.length .. $ ];
	}
	return xs ~ ys;
}
