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;
}