`
主要有三个步骤 1、确定根节点root2、分解环 3 连接子树
1明确是否有可行根节点,有随便找一个;没有:从环中招一个
2为了操作方便,使用并查集寻找环,并将找到第一个环的任意一个节点作为根节点。
3 在确定了根节点之后,如果遇到其他可行根节点,直接连接到已确定根节点即可,就是连接子树的操作。
用t数组来prime找环,依此修改tree数组
这里写代码片
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int tree[200020],t[200020];
int findroot(int x)
{
return x==t[x]?x:t[x]=findroot(t[x]);
}
void prime(int x,int y)
{
int fx=findroot(x);
int fy=findroot(y);
t[fx]=fy;
}
int main()
{
int n,i,j,ans,root;
while(~scanf("%d",&n)&&n>=2)
{
root=-1;
ans=0;
for(i=1;i<=n;i++)
{
scanf("%d",&tree[i]);
t[i]=i;
if(i==tree[i])
root=i;
}
for(i=1;i<=n;i++)
{
if(tree[i]==i&&i==root)
continue;
else if(tree[i]==i&&i!=root)
{
ans++;
tree[i]=root;
prime(i,root);
}
else if(tree[i]!=i&&findroot(tree[i])!=findroot(i))
prime(i,tree[i]);
else if(tree[i]!=i&&findroot(tree[i])==findroot(i))
{
if(root==-1)
{
root=i;
}
tree[i]=root;
ans++;
prime(i,root);
}
}
printf("%d\n",ans);
for(i=1;i<=n;i++)
{
printf("%d",tree[i]);
if(i!=n)printf(" ");
else printf("\n");
}
}
return 0;
}