题解:P10921 Happybob's Puzzle (UBC001A)
Happybob's Puzzle (UBC001A)
思路
黑白染色:对树上的点进行染色,相邻点颜色不同,那么颜色不同的点间的距离一定是奇数。也就是说要求排列中的任意相邻点的颜色不同。
思路有了还需要解决以下问题:
- 怎么判断是否有解?
若黑色和白色点数量之差不大于 \(1\),那么就有解。否则排列内会有相邻点颜色相同,即它们之间的距离为偶数。
- 怎么输出?
用两个优先队列交替从小到大输出,若两个颜色的点数量不同,从点数量多的队列开始输出,否则先输出第一个点序号小的。
时间复杂度:\(O(Tn\log n)\)
代码内有详细注释可以参照。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n; //点数
priority_queue<ll, vector<ll>, greater<ll>> cl[2]; //用以记录两种颜色集合有的点
vector<ll> e[1000005]; //邻接表存图
void clear() {
for(int i=1; i<=n; i++) e[i].clear();
while(!cl[0].empty()) cl[0].pop(); //优先队列的清空
while(!cl[1].empty()) cl[1].pop();
}
void dfs(ll u, ll fa, ll nowcl) {
cl[nowcl].push(u); //把当前元素放入所属队列
for(ll v:e[u]) { //相当于枚举 u 的出边所到达的点的编号
if(v==fa) continue;
dfs(v, u, 1-nowcl);
}
}
void solve() {
ll u, v;
cin >> n;
clear(); //多测别忘了清空
for(int i=1; i<n; i++) {
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1, 0, 0);
ll k=0, check=cl[0].size()-cl[1].size();
if(abs(check)<=1) { //两个队列内元素数量差不大于 1 则可以构成序列
//确定从哪个队列开始
if(cl[0].size()<cl[1].size()) k=1;
else if(!cl[0].empty()&&!cl[1].empty()&&cl[1].top()<cl[0].top()) k=1;
//按顺序输出
while(cl[k].size()) {
cout << cl[k].top() << " ";
cl[k].pop();
k=1-k;
}
} else {
cout << -1;
}
}
int main(){
ios::sync_with_stdio(0);
ll t;
cin >> t;
while(t--) {
solve();
cout << endl;
}
return 0;
}

浙公网安备 33010602011771号