Link
对图进行二分图染色(染为红蓝色),那么可以得到一个结论,所有距离为3的节点的颜色都必不相同。
设(R)为红色节点的个数,(B)为蓝色节点的个数,(X=lfloor frac N 3
floor)。(这里假设(Rleq B))
将 1~n 分类为(1pmod 3,2pmod 3,0pmod3)这三类,则有以下两种情况。
情况1:(Rleq X)
此时可以将所有红节点分配得到(0pmod 3)的节点,这样每一个合法对((i,j))(即((i,j))的距离为3)都会有一个端点是3的倍数,它们的乘积必然是3的倍数。
情况2:(R>X)
此时将红节点分配得到(1pmod 3)的节点,将蓝节点分配得到(2pmod 3)的节点。剩下的(0pmod 3)的节点随意分配。
这样每个合法对((i,j))的端点要么有3的倍数,要么其和为3的倍数。
所以我们也证明了合法的排列分配方案是一定存在的。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 200010;
int n;
vector<int> G[N], v[2];
int p[N];
void dfs(int u, int fa, bool f) {
v[f].push_back(u);
for(auto &i : G[u]) if(i != fa) dfs(i, u, f ^ 1);
}
int main() {
scanf("%d", &n);
for(int u, v, i = 1; i < n; ++i) {
scanf("%d%d", &u, &v);
G[v].push_back(u);
G[u].push_back(v);
}
dfs(1, 1, 1);
if(v[0].size() > v[1].size()) swap(v[0], v[1]);
int x = n / 3;
if((int)v[0].size() <= x) {
int now = 3, T = 0;
for(auto &i : v[0]) p[i] = now, now += 3;
for(auto &i : v[1]) {
if(now > n) now = ++T;
p[i] = now;
now += 3;
}
} else {
int now = 1;
for(auto &i : v[0]) {
p[i] = now;
now += 3;
if(now > n) now = 3;
}
int T = now;
now = 2;
for(auto &i : v[1]) {
p[i] = now;
now += 3;
if(now > n) now = T;
}
}
for(int i = 1; i <= n; ++i) printf("%d ", p[i]);
return 0;
}