CF2052M Managing Cluster 题解
使用贪心或者 DP 求解一个树上的最大匹配
大胆猜测答案一定可以取到
对于上面的最大匹配
我们先引入一个叫做“缩二度点”的操作:假设在
考察
根据不同实现,时间复杂度为
放代码:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
vector<pii> matching(vector<vector<int> > g){
vector<bool> b(g.size());
vector<pii> r;
function<void(int,int)> dfs=[&](int u,int f){
for(int i:g[u])
if(i!=f)dfs(i,u);
if(u&&!b[u]&&!b[f])
r.emplace_back(u,f),b[u]=b[f]=true;
};
return dfs(0,0),r;
} // 求最大匹配
int main(){
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
int t; cin>>t;
while(t--){
int n; cin>>n;
vector<int> a(n<<1);
for(auto &i:a)cin>>i,i--;
vector<vector<int> > g(n<<1),c(n);
for(int i=1;i<n<<1;i++){
int u,v; cin>>u>>v;
g[--u].emplace_back(--v);
g[v].emplace_back(u);
}
auto m=matching(g);
vector<set<int> > s(n);
vector<int> p(n<<1,-1);
for(int i=0;i<n<<1;i++)
s[a[i]].emplace(i);
for(auto [x,y]:m){
p[x]=y,p[y]=x;
c[a[x]].emplace_back(a[y]);
c[a[y]].emplace_back(a[x]);
} // 基于最大匹配建图
vector<bool> b(n),b2(n<<1);
vector<pii> r;
auto solve=[&](int x){
vector<int> v;
function<void(int)> dfs=[&](int u){
b[u]=true,v.emplace_back(u);
for(int i:c[u])
if(!b[i])dfs(i);
};
dfs(x); // 找环 / 链
auto op=[&](int u,int v){
int w=0,x=-1,y=-1;
for(int i:s[u])w^=i;
for(int i:s[u])
for(int j:s[v])
if(p[i]==j&&!b2[w^i])x=w^i,y=j;
r.emplace_back(x,y),b2[x]=b2[y]=true;
s[v].erase(y),s[v].emplace(x);
}; // “缩二度点”操作
for(int l=v.size()-1>>1,r=l+1,f=1;0<=l&&r<v.size();(f=!f)?r++:l--)
f?op(v[l],v[r]):op(v[r],v[l]); // 在链 / 环上缩点
};
for(int i=0;i<n;i++)
if(c[i].size()==1&&!b[i])solve(i); // 链
for(int i=0;i<n;i++)
if(c[i].size()==2&&!b[i])solve(i); // 环
cout<<r.size()<<'\n';
for(auto [x,y]:r)
cout<<x+1<<' '<<y+1<<'\n';
}
return 0;
}