#include <bits/stdc++.h>
using namespace std;

using ll = long long;
using ull = unsigned long long;
using ld = long double;
#define REP(NAME, NUM) for (int NAME = 0; NAME < (NUM); ++NAME)
#define BREP(NAME, NUM) for (int NAME = (NUM)-1; NAME >= 0; --NAME)
#define ALL(NAME) (NAME).begin(), (NAME).end()

#define cMOD 1000000007ULL
#define cINF ((1ull<<62)-1)
#define cINFINT ((1<<30)-1)


class Graph
{
public:
	explicit Graph( int nodeSize )
		: mNodeSize( nodeSize )
		, mEdgeSize( 0 )
		, mEdge( nodeSize )
		, mDepth( nodeSize )
		, mMark( nodeSize )
		, mMark2( 0 )
		, mHas( nodeSize )
		{}
	
	// Edge定義
	struct Edge
	{
		bool operator<( const Edge& other )
		{ return this->cost != other.cost ?
			this->cost < other.cost : this->to < other.to;  }
		int to; int cost; int rev;
	};
	
	// Edge情報を読み取る
	void readEdge_Undirect_NoCost( int m ) { readEdge_( m, false, false ); }
	void readEdge_Direct_NoCost( int m ) { readEdge_( m, true, false ); }
	void readEdge_Undirect_Cost( int m ) { readEdge_( m, false, true ); }
	void readEdge_Direct_Cost( int m ) { readEdge_( m, true, true ); }
	void readEdge_Direct_Flow( int m ) { readEdge_Flow_( m ); }
	
private:
	void readEdge_( int m, bool isDirected, bool isCost )
	{
		REP( i, m )
		{
			int a, b, c = 1, r = -1;
			cin >> a >> b;
			if( isCost ) cin >> c;
			mEdge[a-1].push_back( { b-1, c, -1 } );
			if( !isDirected ) mEdge[b-1].push_back( { a-1, c, r } );
			++mEdgeSize;
		}
	}
	void readEdge_Flow_( int m )
	{
		REP( i, m )
		{
			int a, b, c;
			cin >> a >> b >> c;
			mEdge[a-1].push_back( { b-1, c, int(mEdge[b-1].size()) } );
			mEdge[b-1].push_back( { a-1, 0, int(mEdge[a-1].size() - 1) } );
			++mEdgeSize;
		}
	}
	
public:
	// 必要なときだけメモリ確保するように
	void assignMark2()
	{
		vector<int> tmp( mNodeSize, cINFINT );
		mMark2.assign( mNodeSize, tmp );
	}
	void setupMark2ForCost()
	{
		REP( i, mNodeSize )
		{
			mMark2[i][i] = 0;
			for( const auto& e : mEdge[i] ) mMark2[i][e.to] = e.cost;
		}
	}


public:
	// MARK構造体
	struct MARK
	{
		int num = 0;
		int distAll = 0;
		int maxOp = 0;
		MARK& operator+=( const MARK& rhs )
		{
			this->num += rhs.num;
			this->distAll += rhs.distAll;
			return *this;
		}
	};

public:
	int mNodeSize; // VertexSize
	int mEdgeSize; // EdgeSize
	vector< vector< Edge > > mEdge; // 隣接リスト
	
	// 作業用変数
	vector<int> mDepth /* Used */;
	vector<MARK> mMark;
	vector<bool> mHas;
	// 必要なときだけメモリ確保するように
	vector< vector<int> > mMark2;
};

// O( N )
void dfs_tree_depth_( Graph& g, int v )
{
	vector<int> childList;
	for( const auto& e : g.mEdge[v] )
	{
		if( g.mDepth[e.to] >= 0 ) continue;
		g.mDepth[e.to] = g.mDepth[v] + 1;
		childList.push_back( e.to );
		dfs_tree_depth_( g, e.to );
		/**/g.mMark[e.to].distAll += g.mMark[e.to].num;
	}
	auto& m = g.mMark[v];
	REP( i, childList.size() ) m += g.mMark[childList[i]];
	if( childList.size() == 1 ) m.maxOp = g.mMark[childList[0]].maxOp;
	else if( childList.size() > 1 )
	{
		int maxxxDist = 0, maxxxIdx = 0;
		REP( i, childList.size() ) if( maxxxDist <= g.mMark[childList[i]].distAll )
		{ maxxxDist = g.mMark[childList[i]].distAll; maxxxIdx = childList[i]; }
		int leftDist = maxxxDist - g.mMark[maxxxIdx].maxOp * 2;
		REP( i, childList.size() ) if( maxxxIdx != childList[i] )
		{ leftDist -= g.mMark[childList[i]].distAll; }
		m.maxOp = ( m.distAll - max( leftDist, 0 ) ) / 2;
	}
	if( g.mHas[v] ) ++m.num;
	//cout << v << " " << m.num << " " << m.distAll << " " << m.maxOp << endl;
}
void dfs_tree_depth( Graph& g, int rootNode )
{
	fill( ALL( g.mDepth ), -1 );
	fill( ALL( g.mMark ), Graph::MARK() );
	g.mDepth[rootNode] = 0;
	dfs_tree_depth_( g, rootNode );
	//cout << "----" << endl;
}

int main()
{
	int n, m;
	cin >> n; m = n - 1;
	string s; cin >> s;
	Graph g( n );
	g.readEdge_Undirect_NoCost( m );
	REP(i,n) g.mHas[i] = s[i]=='1';
	
	int cnt = 2000 * 2000;
	REP(i,n)
	{
		dfs_tree_depth(g,i);
		int sum = g.mMark[i].distAll;
		if( sum % 2 == 0 && g.mMark[i].maxOp == sum / 2 )
			cnt = min( cnt, sum / 2 );
	}
	if( cnt == 2000 * 2000 ) cout << -1 << endl;
	else cout << cnt << endl;

	return 0;
}

Measured memory_bytes: 640