#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 cInfInt ((1<<30)-1)


class Graph
{
public:
	explicit Graph( int nodeSize )
		: mNodeSize( nodeSize )
		, mEdgeSize( 0 )
		, mEdge( nodeSize )
		, mUsed( nodeSize )
		, mMark( nodeSize )
		, mMark2( 0 )
		{}
	
	// Edge定義
	struct Edge
	{
		Edge( int to_, int cost_ ) { to = to_; cost = cost_; }
		bool operator<( const Edge& other )
		{ return this->cost != other.cost ?
			this->cost < other.cost : this->to < other.to;  }
		int to; int cost;
	};
	
	// 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 ); }
	
private:
	void readEdge_( int m, bool isDirected, bool isCost )
	{
		REP( i, m )
		{
			int a, b, c = 1;
			cin >> a >> b;
			if( isCost ) cin >> c;
			mEdge[a-1].push_back( Edge( b-1, c ) );
			if( !isDirected ) mEdge[b-1].push_back( Edge( a-1, c ) );
			++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:
	int mNodeSize; // VertexSize
	int mEdgeSize; // EdgeSize
	vector< vector< Edge > > mEdge; // 隣接リスト
	
	// 作業用変数
	vector<bool> mUsed;
	vector<int> mMark;
	// 必要なときだけメモリ確保するように
	vector< vector<int> > mMark2;
};

int dfs_tree_farthest_( Graph& g, int v )
{
	int retV = v;
	for( const auto& e : g.mEdge[v] )
	{
		if( g.mUsed[e.to] ) continue;
		g.mUsed[e.to] = true;
		g.mMark[e.to] = g.mMark[v] + 1;
		auto u = dfs_tree_farthest_( g, e.to );
		if( g.mMark[u] > g.mMark[retV] ) retV = u;
	}
	return retV;
}
pair<int /* farthestNode */, int /* length */>
dfs_tree_farthest( Graph& g, int startNode )
{
	fill( ALL( g.mUsed ), 0 ); fill( ALL( g.mMark ), -1 );
	g.mUsed[startNode] = true;
	g.mMark[startNode] = 0;
	auto node = dfs_tree_farthest_( g, startNode );
	return pair<int,int>( node, g.mMark[node] );
}

struct CaterpillarInfo
{
	bool isCaterPillarInfo = false;	// キャタピラ判定
	vector<int> diameterNode; 			// 直径のノード番号が順に入っている
	vector<vector<int>> footNode;		// 直径のノードから出る足ノード
};
void judgeCaterpillar( Graph& g, CaterpillarInfo& outInfo /* 初期化済み */ )
{ // RVOを信用しない
	auto& dNode = outInfo.diameterNode;
	auto farNode = dfs_tree_farthest( g, 0 ); // 木の前
	int curNode = farNode.first;
	fill( ALL( g.mUsed ), false );
	while( curNode >= 0 )
	{
		dNode.push_back( curNode ); g.mUsed[curNode] = true;
		int nextNode = -1;
		for( auto& e : g.mEdge[curNode] )
		if( !g.mUsed[e.to] && g.mEdge[e.to].size() > 1 )
		{
			if( nextNode >= 0 ) return;
			else nextNode = e.to;
		}
		if( nextNode < 0 ) for( auto& e : g.mEdge[curNode] ) if( !g.mUsed[e.to] )
		{ nextNode = e.to; break; }
		curNode = nextNode;
	}
	outInfo.footNode.assign( dNode.size(), vector<int>() );
	REP( i, dNode.size() - 1 )
	{
		if( i == 0 ) continue;
		for( auto& e : g.mEdge[dNode[i]] )
		if( e.to != dNode[i - 1] && e.to != dNode[i + 1] &&
			g.mEdge[e.to].size() == 1 )
				outInfo.footNode[i].push_back( e.to );
	}
	outInfo.isCaterPillarInfo = true; return;
}

int main()
{
	int n;
	cin >> n;
	Graph g( n );
	g.readEdge_Undirect_NoCost( n - 1 );
	
	CaterpillarInfo info;
	judgeCaterpillar( g, info );
	if( !info.isCaterPillarInfo ) cout << "-1" << endl;
	else
	{
		int cur = 1;
		vector<int> ans0, ans1;
		REP( i, info.diameterNode.size() )
		{
			for( int j = cur + 1; j <= cur + info.footNode[i].size(); ++j )
				ans0.push_back(j);
			ans0.push_back(cur);
			cur += 1 + info.footNode[i].size();
		}
		cur = 1;
		BREP( i, info.diameterNode.size() )
		{
			for( int j = cur + 1; j <= cur + info.footNode[i].size(); ++j )
				ans1.push_back(j);
			ans1.push_back(cur);
			cur += 1 + info.footNode[i].size();
		}
		if( ans0 < ans1 ) REP( i, ans0.size() ) cout << ans0[i] << " ";
		else REP( i, ans1.size() ) cout << ans1[i] << " ";
	}
	
	return 0;
}

Measured memory_bytes: 13436