题目大意
给定2k个队伍分别住在2k个城市里,需要设定若干个城市,然后选取2个队伍要在它们的最短路径上设一个城市作为休息站
要求设立最少的休息站,然后输出如何安排2个队伍
首先若干个其实就是在坑人,实际上1个就可以了
这一个点就是树的权值重心。
权值重心的定义:若选取权值重心为根,则它的任意子树的权值和不会大于所有子树权值和的二分之一
那么接下来证明权值重心是可行的
只需要构造出来一组分组即可
我是这么构造的
先搜每一个子树,搜集齐k个点放到A,然后继续搜集剩下的点放到B,如果权值重心上也有队伍,那么就把它加到B
然后依次输出A[i],B[i]即可
这样做是可行的,因为任意子树的权值和不会大于所有子树权值和的二分之一。(稍微想想就可以知道啦)
#include <iostream> #include <vector> #include <queue> using namespace std; const int maxn = 222222; vector<int> G[maxn]; queue<int> Q[2]; int f[maxn], v[maxn], sz[maxn], son[maxn]; int n, k, x, y, X; void dfs(int x, int fa) { for(int i = 0; i < G[x].size(); i++) { int to = G[x][i]; if(fa == to) continue; dfs(to, x); sz[x] += sz[to]; son[x] = max(son[x], sz[to]); } son[x] = max(son[x], 2*k - sz[x]); } void dfs2(int x, int fa, int c) { if(!f[x] && Q[c-1].size() < k && v[x]) { f[x] = c; Q[c-1].push(x); } for(int i = 0; i < G[x].size(); i++) { int to = G[x][i]; if(fa == to) continue; dfs2(to, x, c); } } int main() { cin>>n>>k; for(int i = 1; i < n; i++) { cin>>x>>y; G[x].push_back(y); G[y].push_back(x); } for(int i = 1; i <= 2*k; i++) cin>>x, sz[x] = v[x] = 1; dfs(1, 0); for(int i = 1; i <= n; i++) if(son[i] <= k) X = i; cout<<1<<endl<<X<<endl; for(int i = 0; i < G[X].size(); i++) { if(Q[0].size() < k) dfs2(G[X][i], X, 1); if(Q[0].size() == k) dfs2(G[X][i], X, 2); } if(Q[1].size() == k-1) Q[1].push(X); while(!Q[0].empty()) { cout<<Q[0].front()<<" "<<Q[1].front()<<" "<<X<<endl; Q[0].pop(); Q[1].pop(); } }
时间: 2024-10-22 10:19:02