#include <iostream>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <map>
#include <algorithm>
#include <iomanip>
#include <math.h>
#include <string.h>
using namespace std;
using ll = long long; using pll = pair<ll, ll>;
using vl = vector<ll>; using vll = vector<vl>; using vpll = vector<pll>;
//**関数リスト**//
int ctoi(char c) {
	switch (c) {
	case '0': return 0;
	case '1': return 1;
	case '2': return 2;
	case '3': return 3;
	case '4': return 4;
	case '5': return 5;
	case '6': return 6;
	case '7': return 7;
	case '8': return 8;
	case '9': return 9;
	default: return 0;
	}
}
bool pairCompare(const pll firstElof, pll secondElof)
{
	return firstElof.first > secondElof.first;
}
ll nod(ll F) {
	ll keta = 1;
	while (F / 10 > 0) {
		keta++; F /= 10;
	}
	return keta;
}
ll gcd(ll x, ll y) {
	ll r;
	if (x < y) {
		swap(x, y);
	}
	while (y > 0) {
		r = x % y;
		x = y;
		y = r;
	}
	return x;
}
ll lcm(ll x, ll y) {
	return x * y / gcd(x, y);
}
ll isPrime(ll x) {
	ll i;
	if (x < 2) {
		return 0;
	}
	else if (x == 2) {
		return 1;
	}
	else if (x % 2 == 0) {
		return 0;
	}
	else {
		for (i = 3; i * i <= x; i += 2) {
			if (x % i == 0) {
				return 0;
			}
		}
		return 1;
	}
}
void eratos(vl isPrime) {
	//(注)isPrimeのサイズはN+1にする！実際にはmain内に配置して使用
	ll i, j;
	for (i = 0; i < isPrime.size(); i++) {
		isPrime[i] = 1;
	}
	isPrime[0] = 0; isPrime[1] = 0;
	for (i = 2; i * i <= isPrime.size() - 1; i++) {
		if (isPrime[i] == 1) {
			j = i * 2;
			while (j <= isPrime.size() - 1) {
				isPrime[j] = 0;
				j = j + i;
			}
		}
	}
}
ll modinv(ll a, ll m) {
	ll b = m, u = 1, v = 0;
	while (b) {
		ll t = a / b;
		a -= t * b; swap(a, b);
		u -= t * v; swap(u, v);
	}
	u %= m;
	if (u < 0) u += m;
	return u;
}
ll alphabet(char C) {
	ll b = 0; ll key = 0;
	if (C == 'a') { return b; }b++;
	if (C == 'b') { return b; }b++;
	if (C == 'c') { return b; }b++;
	if (C == 'd') { return b; }b++;
	if (C == 'e') { return b; }b++;
	if (C == 'f') { return b; }b++;
	if (C == 'g') { return b; }b++;
	if (C == 'h') { return b; }b++;
	if (C == 'i') { return b; }b++;
	if (C == 'j') { return b; }b++;
	if (C == 'k') { return b; }b++;
	if (C == 'l') { return b; }b++;
	if (C == 'm') { return b; }b++;
	if (C == 'n') { return b; }b++;
	if (C == 'o') { return b; }b++;
	if (C == 'p') { return b; }b++;
	if (C == 'q') { return b; }b++;
	if (C == 'r') { return b; }b++;
	if (C == 's') { return b; }b++;
	if (C == 't') { return b; }b++;
	if (C == 'u') { return b; }b++;
	if (C == 'v') { return b; }b++;
	if (C == 'w') { return b; }b++;
	if (C == 'x') { return b; }b++;
	if (C == 'y') { return b; }b++;
	if (C == 'z') { return b; }
	return -1;
}
void bitSearch(ll n) {
	//実際にはコピーして中身を改変して使う
	ll i, j;
	for (i = 0; i < pow(2, n); i++) {
		ll p = i;
		for (j = 0; j < n; j++) {
			cout << p % 2;
			p /= 2;
		}
		cout << endl;
	}
}
void dfsx(ll now, ll C) {
	stack<ll> S;
	S.push(now);
	//color[now] = C;
	//while (!S.empty()) {
		ll u = S.top();
		S.pop();
		//for (ll i = 0; i < road[u].size(); i++) {
			//ll v = road[u][i];
			//if (color[v] == 0) {
				//dfs(v, C);
			//}
		//}
	//}
}
void bfs(ll now) {
	//中身は毎回書き換えて使用
	queue<ll> Q;
	Q.push(now);
	ll u;
	while (!Q.empty()) {
		u = Q.front();
		Q.pop();
		//ll v=;
		//Q.push(v);
	}
}
void dijkstra(ll s) {
	priority_queue<pll> PQ;
	//vl D(N), color(N);
	//for (i = 0; i < N; i++) {
	//	D[i] = INF;
	//	color[i] = 0;
	//}
	//D[s] = 0;
	PQ.push(make_pair(0, s));
	//color[0] = 1;
	ll q = -1;
	while (!PQ.empty()) {
		pll f = PQ.top();
		PQ.pop();
		ll u = f.second;
		//color[u] = 2;
		//if (D[u] < f.first * q) {
		//	continue;
		//}
		//for (j = 0; j < path[u].size(); j++) {
			//ll v = path[u][j].first;
			//if (color[v] == 2) {
			//	continue;
			//}
			//if (D[v] > D[u] + path[u][j].second) {
			//	D[v] = D[u] + path[u][j].second;
			//	color[v] = 1;
			//	PQ.push(make_pair(D[v] * q, v));
			//}
		//}
	}
	//cout << (D[N - 1] == INF ? -1 : D[N - 1]);
}
class UnionFind {
	public:
		vl rank, par, siz;
		UnionFind(){}
		UnionFind(ll N){
			rank.resize(N, 0);
			par.resize(N, 0);
			siz.resize(N, 1);
			init(N);
		}
		void init(ll N) {
			for (ll i = 0; i < N; i++) {
				par[i] = i;
				rank[i] = 0;
			}
		}
		ll find(ll x) {
			if (par[x] == x) {
				return x;
			}
			else {
				return par[x] = find(par[x]);
			}
		}
		void unite(ll x, ll y) {
			x = find(x);
			y = find(y);
			if (x != y) {
				if (rank[x] < rank[y]) {
					par[x] = y;
					siz[y] += siz[x];
				}
				else {
					par[y] = x;
					siz[x] += siz[y];
					if (rank[x] == rank[y]) rank[x]++;
				}
			}
		}
		bool issame(ll x, ll y) {
			return find(x) == find(y);
		}
		ll size(ll x) {
			return siz[find(x)];
		}
};
//**定義場所**//
ll i, j, k, l, m, n, N, M, K, H, W, L;
string S, T;
ll MOD = 1000000007; ll ans = 0; ll INF = 9999999999999999;
vll path;
vl flag;
vl color;
vll PL;
//***********//
void dfs(ll now) {
	stack<ll> S;
	S.push(now);
	flag[now] = 1;
	set<ll> NL;
	ll s = PL[now].size();
	K = max(K, s);
	for (j = 0; j < s; j++) {
		NL.insert(j + 1);
	}
	for (j = 0; j < s; j++) {
		if (color[PL[now][j]] != 0) {
			NL.erase(color[PL[now][j]]);
		}
	}
	for (j = 0; j < s; j++) {
		if (color[PL[now][j]] == 0) {
			color[PL[now][j]] = *NL.begin();
			NL.erase(*NL.begin());
		}
	}
	NL.clear();
	while (!S.empty()) {
	ll u = S.top();
	S.pop();
	for (ll i = 0; i < path[u].size(); i++) {
		ll v = path[u][i];
		if (flag[v] == 0) {
			dfs(v);
		}
	}
}
}
int main() {
	cin >> N;
	path.resize(N);
	flag.resize(N);
	for (i = 0; i < N; i++) {
		flag[i] = 0;
	}
	color.resize(N - 1);
	PL.resize(N);
	for (i = 0; i < N - 1; i++) {
		color[i] = 0;
		ll a, b;
		cin >> a >> b;
		PL[a - 1].push_back(i);
		PL[b - 1].push_back(i);
		path[a - 1].push_back(b - 1);
		path[b - 1].push_back(a - 1);
	}
	K = 0;
	dfs(0);
	cout << K << endl;
	for (i = 0; i < N - 1; i++) {
		cout << color[i] << endl;
	}
}

Measured memory_bytes: 55040