一堆 Cornner Case 的大分討,我們全隊一邊寫一邊補情況,WA 了五發終於幹過去了
首先當圖中存在某個環時,我們只要給環上的所有點賦值為 \(1\) 即可;又因為圖連通所以只要考慮樹的情況即可
考慮如果存在一個度數 \(\ge 4\) 的點,將其賦值為 \(2\) 並將其周圍的四個點賦值為 \(1\) 即可
如果存在兩個及以上度數為三的點,只要將其中兩個的路徑上所有點賦值為 \(2\),並在端點處各選兩個點賦值為 \(1\) 即可
難點在於有且僅有一個度數為三的點的情況,因為我們很容易證明一條鏈的情況是無解的
考慮此時的圖一定形如一箇中心點,往外延申出三條鏈,不妨將這三條鏈的長度記為 \(a,b,c(a\le b\le c)\)
考慮找出一些最小的有解結構,方法可以是人類智慧也可以是爆搜,最後發現以下三種 Case 是合法的:
然後這題就做完了,判斷一個圖是否滿足上述條件即可,程式碼是徐神寫的
#include <bits/stdc++.h>
std::vector<int> work() {
int n, m; std::cin >> n >> m;
std::vector<std::vector<int>> out(n, std::vector<int>());
for(int i = 0, f, t; i < m; ++i) {
std::cin >> f >> t;
f--; t--;
out[f].push_back(t);
out[t].push_back(f);
}
std::vector<int> ans(n, 0);
std::vector<bool> vis(n, false);
std::function<bool(int, int)> dfs = [&](int cur, int fa) -> bool {
vis[cur] = true;
for(auto out: out[cur]) {
if(out == fa) continue;
if(vis[out] || dfs(out, cur))
return ans[cur] = 1, vis[cur] = true;
}
return false;
};
for(int i = 0; i < n; ++i) if(!vis[i] && dfs(i, -1)) return ans;
for(int i = 0; i < n; ++i) if(out[i].size() >= 4) {
ans[i] = 2;
for(int j = 0; j < 4; ++j) ans[out[i][j]] = 1;
return ans;
}
auto ahaha = [&](auto self, int cur, int fa) -> int {
for(auto out: out[cur]) if(out != fa) return self(self, out, cur) + 1;
return 1;
};
auto fill = [&](auto self, int cur, int fa, std::vector<int> val) -> void {
if(val.empty()) return ;
ans[cur] = val.back(); val.pop_back();
for(auto out: out[cur]) if(out != fa) self(self, out, cur, val);
};
vis.assign(n, false);
auto dfs2 = [&](auto self, int cur, int fa) -> int {
vis[cur] = true;
if(out[cur].size() == 3) return ans[cur] = 2, cur;
for(auto out: out[cur]) if(out != fa) {
int res = self(self, out, cur);
if(res >= 0) return ans[cur] = 2, res;
}
return -1;
};
bool flag = false;
for(int i = 0; i < n && !flag; ++i) if(!vis[i] && out[i].size() == 3) {
vis[i] = true;
for(auto out: out[i]) {
if(flag) break;
int res = dfs2(dfs2, out, i);
// std::cerr << "res = " << res << char(10);
if(res >= 0) {
ans[i] = 2;
flag = true;
}
}
}
if(flag) {
for(int i = 0; i < n; ++i) if(ans[i] == 2) for(auto out: out[i]) if(ans[out] == 0) ans[out] = 1;
return ans;
}
for(int i = 0; i < n; ++i) if(out[i].size() == 3) {
std::pair<int, int> len[3];
for(int j = 0; j < 3; ++j) len[j] = {ahaha(ahaha, out[i][j], i), out[i][j]};
std::sort(len, len + 3);
// std::cerr << "len[] = [";
// for(int j = 0; j < 3; ++j) std::cerr << len[j].first << (j == 2 ? "]\n" : ", ");
if(len[0].first >= 2 && len[1].first >= 2 && len[2].first >= 2) {
ans[i] = 3;
fill(fill, len[0].second, i, std::vector<int>{1, 2});
fill(fill, len[1].second, i, std::vector<int>{1, 2});
fill(fill, len[2].second, i, std::vector<int>{1, 2});
return ans;
}
if(len[0].first >= 1 && len[1].first >= 2 && len[2].first >= 5) {
ans[i] = 6;
fill(fill, len[0].second, i, std::vector<int>{3});
fill(fill, len[1].second, i, std::vector<int>{2, 4});
fill(fill, len[2].second, i, std::vector<int>{1, 2, 3, 4, 5});
return ans;
}
if(len[0].first >= 1 && len[1].first >= 3 && len[2].first >= 3) {
ans[i] = 4;
fill(fill, len[0].second, i, std::vector<int>{2});
fill(fill, len[1].second, i, std::vector<int>{1, 2, 3});
fill(fill, len[2].second, i, std::vector<int>{1, 2, 3});
return ans;
}
}
return {};
}
int main() {
std::ios::sync_with_stdio(false);
int t; std::cin >> t; while(t--) {
auto ans = work();
if(ans.empty()) std::cout << "NO\n";
else {
std::cout << "YES\n";
int n = ans.size();
for(int i = 0; i < n; ++i) std::cout << ans[i] << char(i == n - 1 ? 10 : 32);
}
}
return 0;
}