Fix a Tree
A tree is an undirected connected graph without cycles.
Let’s consider a rooted undirected tree with n vertices, numbered 1 through n. There are many ways to represent such a tree. One way is to create an array with n integers p1, p2, …, pn, where pi denotes a parent of vertex i (here, for convenience a root is considered its own parent).
Given a sequence p1, p2, …, pn, one is able to restore a tree:
- There must be exactly one index r that pr = r. A vertex r is a root of the tree.
- For all other n - 1 vertices i, there is an edge between vertex i and vertex pi.
A sequence p1, p2, …, pn is called valid if the described procedure generates some (any) rooted tree. For example, for n = 3 sequences (1,2,2), (2,3,1) and (2,1,3) are not valid.
You are given a sequence a1, a2, …, an, not necessarily valid. Your task is to change the minimum number of elements, in order to get a valid sequence. Print the minimum number of changes and an example of a valid sequence after that number of changes. If there are many valid sequences achievable in the minimum number of changes, print any of them.
题目大意:给你一个大小为n的序列 p[],p[i] 代表结点 i 的父亲是 p[i];p[i]==i 表示 i 是树的根结点,因为给的 p[] 不一定是一颗树,也不一定连通,如果要让这 n 个结点连成一颗树,最少更改父节点的次数;
分析题目可知,每个结点只有一个父节点,也就是说每个点的入度都为1,所以p[]序列要不就是树,要不就是环,可能是树和环的混合,因为图不一定连通;
这题就可以先找到一个根,并且记录每个环,把这些环拆开连接在这个根上面,就是一颗完整的n个结点的树了;
还要注意不一定能找到根,这时就要从环里面定义一个根,特判一下;
代码:
#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=200100;
const int M=2000100;
const LL mod=1e9+7;
int n,p[N],fa[N],rt,loop[N],cnt;
int find(int p){
if(p==fa[p]) return p;
return fa[p]=find(fa[p]);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&p[i]),fa[i]=i;
for(int i=1;i<=n;i++){
int fx=find(i),fy=find(p[i]);
if(fx==fy){
if(i==p[i]) rt=p[i];
loop[++cnt]=i;//环
}
else fa[find(fx)]=find(fy);
}
int ans=0;
if(!rt){
for(int i=1;i<=n;i++) if(find(i)==i) rt=i;
for(int i=1;i<=cnt;i++){
ans++;
p[loop[i]]=rt;
}
}
else{
for(int i=1;i<=cnt;i++){
if(loop[i]!=rt){
ans++;
p[loop[i]]=rt;
}
}
}
printf("%d\n",ans);
for(int i=1;i<=n;i++) printf("%d ",p[i]);
return 0;
}