Codeforces Round #363 (Div. 2) D. Fix a Tree
2016-07-21 10:45
260 查看
题意
给出一组数表示每个节点的父节点,要修改最少的边使得这些节点变成一棵树
思路
根据题意,不符合要求的有两种可能,图中有环路,或者树根不止一个。
用并查集进行分类,将相连的节点划分到一个集合,随机指派一个符合要求的根节点(其父节点为自己)为最终的root,将其他集合若没有环路,则直接将其根节点指向root。若有环,则在环中找一个节点将其父节点修改为root。寻找环的方法:如果其父节点不是自己但是其所在集合的代表元素是它,那么就修改它的父节点就好了。
代码如下
给出一组数表示每个节点的父节点,要修改最少的边使得这些节点变成一棵树
思路
根据题意,不符合要求的有两种可能,图中有环路,或者树根不止一个。
用并查集进行分类,将相连的节点划分到一个集合,随机指派一个符合要求的根节点(其父节点为自己)为最终的root,将其他集合若没有环路,则直接将其根节点指向root。若有环,则在环中找一个节点将其父节点修改为root。寻找环的方法:如果其父节点不是自己但是其所在集合的代表元素是它,那么就修改它的父节点就好了。
代码如下
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n; int fa[200005]; int p[200005]; int find(int v){ return fa[v] = fa[v] == v ? v : find(fa[v]); } void merge(int a, int b) { int x = find(a); int y = find(b); fa[x] = y; } int main() { // freopen("data.txt","r",stdin); scanf("%d",&n); int ans = 0; int root = -1; for(int i = 1; i <= n; ++i){ scanf("%d",&p[i]); fa[i] = i; if(p[i] == i && root == -1)root = i; } for(int i = 1; i <= n; ++i){ merge(i,p[i]); } for(int i = 1; i <= n; ++i){ if(root == -1 && p[i] == i){ root = i; } else if( i == find(i) && p[i] != i){ ans ++; p[i] = root == -1 ? i : root; if(p[i] == i)root = i; merge(i,root); } else if(p[i] == i && i != root){ ans++; p[i] = root; merge(i,root); } } printf("%d\n",ans); printf("%d",p[1]); for(int i = 2; i <= n; ++i){ printf(" %d",p[i]); } puts(""); return 0; }
相关文章推荐
- 贪心算法
- poj1006 Biorhythms(模拟)
- iOS 页面之间的传值总结
- 13. Roman to Integer
- B-tree/B+tree/B*tree
- HTML5里原生的右键菜单创建方法
- Oil Deposits (dfs)
- 关于js无法设置input的value的问题
- 多线程(基础篇)
- hdu 1686 kmp(求子串出现个数)
- Android实用技术: CoordinatorLayout使用详解
- RocketMQ系列
- Linux之进程终止
- Linux之fork与vfork区别
- Android 依赖
- 全面了解Java中的内部类和匿名类
- HDU 1201 18岁生日
- Python小实验——向类传递参数
- HTTP.Socket.TCP详解
- 设计模式——适配器模式