並查集判環+思維 Codeforces Round #363 (Div. 2) D題 Fix a Tree

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:

  1. There must be exactly one index r that pr = r. A vertex r is a root of the tree.
  2. 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章