题目链接
题意:
一棵以
1
1
为根个节点的树,一些节点的父亲已知,现在你要设置这些父亲节点未知的节点的父亲,使得这棵树的父亲节点
−
−
儿子节点这样的匹配最大。
思路:
可以处理处出每棵已知树的最大匹配,然后对于根节点已经匹配的, 显然这个根节点的父节点挂在
1
1
是最优的,对于根节点没有匹配的树,就看已经连接好的树中是否有未匹配的节点,有的话连上,匹配,否则这棵树的父亲节点也挂在
1
1
<script type="math/tex" id="MathJax-Element-801">1</script>,然后将其原来所在的树的未匹配的节点插入进去, 下次利用。
#include<bits/stdc++.h>
typedef long long ll;
const int maxn = 1e5 + 10;
using namespace std;
typedef pair<int, int> P;
int n, m, T, kase = 1;
vector<int> G[maxn], un_match[maxn];
int pre[maxn], match[maxn];
int rt[maxn], cnt;
set<int> st;
bool have_match(int v, int root) {
rt[v] = root;
bool res = false;
for(int i = 0; i < G[v].size(); i++) {
int x = G[v][i];
if(!have_match(x, root) && !res) {
match[v] = match[x] = true;
res = true; cnt++;
}
}
return res;
}
int main() {
freopen("hidden.in", "r", stdin);
freopen("hidden.out", "w", stdout);
while(scanf("%d", &n) != EOF) {
cnt = 0; st.clear();
for(int i = 0; i < maxn; i++) {
match[i] = rt[i] = 0;
G[i].clear();
un_match[i].clear();
}
for(int i = 2; i <= n; i++) {
scanf("%d", &pre[i]);
G[pre[i]].push_back(i);
}
queue<int> que0;
priority_queue<P> que1;
G[0].push_back(1);
for(int i = 0; i < G[0].size(); i++) {
int root = G[0][i];
have_match(root, root);
}
for(int i = 1; i <= n; i++) if(!match[i]) un_match[rt[i]].push_back(i);
G[0].pop_back();
for(int i = 0; i < G[0].size(); i++) {
int x = G[0][i];
if(match[x]) que0.push(x);
else que1.push(P(un_match[x].size(), x)); ///每次取最多没有匹配的点
}
for(int i = 0; i < un_match[1].size(); i++) st.insert(un_match[1][i]);
while(!que0.empty()) {
int u = que0.front(); que0.pop();
pre[u] = 1;
for(int i = 0; i < un_match[u].size(); i++) st.insert(un_match[u][i]); ///未匹配的点放进去
}
while(!que1.empty()) {
int u = que1.top().second; que1.pop();
if(!st.empty()) {
int v = *st.begin();
for(int i = 0; i < un_match[u].size(); i++) st.insert(un_match[u][i]);
st.erase(v);
st.erase(u); ///记得删除u,因为u已经匹配了
pre[u] = v;
cnt++;
} else {
pre[u] = 1;
for(int i = 0; i < un_match[u].size(); i++) st.insert(un_match[u][i]);
}
}
printf("%d\n", cnt);
for(int i = 2; i <= n; i++) printf("%d%c", pre[i], i < n ? ' ' : '\n');
}
return 0;
}