题意:
给出n个点的父节点,问最少修改几个点能使整个图变成一棵树。
题解:
给出的图可能包括多个树、环,要使图变成树则要先将环解开,再将树合并。
用并查集保存树,再通过dfs判断是否存在环,解开环要注意一些细节。
#include<iostream>
#include <stdio.h>
#include <algorithm>
#include <math.h>
#include<stdlib.h>
#include <string.h>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<time.h>
using namespace std;
#define MAX_N 200005
#define inf 0x7fffffff
#define LL long long
#define ull unsigned long long
#define mod 10007
LL INF=9e18;
int n;
int par[MAX_N];
int ans[MAX_N];
vector<int>G[MAX_N];
int find(int x)
{
return x==par[x]?x:par[x]=find(par[x]);
}
void unite(int x,int y)
{
x = find(x);
y = find(y);
par[x] = y;
}
void init()
{
for(int i=1;i<=n;i++)
par[i] = i;
}
bool dfs(int u,int v,int s)
{
for(int i=0;i<G[u].size();i++) {
if(G[u][i] == s || G[u][i] == v) {
return true;
}
else {
if(dfs(G[u][i], u, s))
return true;
}
}
return false;
}
int main()
{
cin >> n;
init();
for(int i=1;i<=n;i++) {
int fa;
scanf("%d",&fa);
if(i != fa)
G[i].push_back(fa);
ans[i] = fa;
unite(i, fa);
}
int cnt = -1;
int fa;
int Fa = 0;
for(int i=1;i<=n;i++) {
if(par[i] == i) {
cnt++;
fa = i;
if(!dfs(i, 0, i))
Fa = i;
}
}
if(!Fa) {
cnt++;
ans[fa]=fa;
}
else {
fa = Fa;
}
for(int i=1;i<=n;i++) {
if(par[i] == i && i != fa) {
ans[i] = fa;
par[i] = fa;
}
}
cout << cnt << endl;
for(int i=1;i<=n;i++) {
printf("%d%c",ans[i],i==n?'\n':' ');
}
}