您的位置:首页 > 其它

NHIP(2015)解题报告(第3题)

2016-02-15 19:34 176 查看
NHIP(2015)解题报告(第3题)
第三题:树(tree)
[题意分析]

其实考的是如何合并集和,合并集合有两种方法:
方法一:
时间复杂度:o(2n)

Id

1
2
3
4
5
6
7
D
1
2
3
4
5
6
7
当输入(1,2)时:

Id

1
2
3
4
5
6
7
D
1
2
1
3
4
5
6
7
(1)找出1,2
(2)判断1,2的“祖先”是否相同。

a.相同的,就把边数加1;

b.不相同,就把大的那个“祖先”换成小的那个“祖先”,

在寻找出更原来大的“祖先”相同的,都变成小的那个祖先。
但此题的数据范围过大,这种方法会超时,不加以使用。
方法二:
时间复杂度:o(1)

根据并查集的思路,即可解决这道题:





这样可以提高效率,因此使程序不易超时:



[程序参考]
#include <iostream>
#include <fstream>
using namespace std;
ifstream fin ("tree.in");
ofstream fout ("tree.out");
#define cin fin
#define cout fout
const int mx=1000001;
int pt[mx],fa[mx],line[mx],ans=0;
int m,n,fx,fy,x,y;

int u_f(int x)
{

int root=x;

while (fa[root]!=root)

root=fa[root]; //顺藤摸瓜,找x的最前面的祖先;

while (fa[x]!=x) //将x到root这条藤上的所有点的祖先都置为root;

{

int t=fa[x]; //t为x的父节点;

fa[x]=root; //将x的父节点的祖先置为root;

x=t; //再将x置为他的父节点,然后再从父节点为出发点,重置;

}

return root; //返回祖先节点;

}

int main()
{

int i;

cin>>m>>n;

for (i=1;i<=m;i++) //初始化每个点

{

fa[i]=i; //第i个点的父亲就是他自己,

pt[i]=1; //作为1个“树”——它包含1个节点(它自己)

line[i]=0; //和0条边

}

for (i=0;i<n;i++) //输入n条边,通过并查集,找每个点所在的集合,以及每个集合的点数边数

{

cin>>x>>y;

fx=u_f(x); //找x点的祖先

fy=u_f(y); //找y点的祖先

if (fx!=fy) //加入这条边上的两点的祖先各不相同,

{

fa[fy]=fx;
//则将y点的祖先置为x点的祖先;

line[fx]+=1+line[fy];
//x点所在集合的边数=x点所在集合的边数+y点所在集合的边数+1

pt[fx]+=pt[fy];
//x点所在集合的节点数=x点所在集合的节点数+y点所在集合的节点数

} else line[fx]++; //如果x点祖先和y点祖先相同,则x点和y点在同一集合,则该集合多出1条边;

}

for (i=1;i<=m;i++) //统计m个节点中,祖先是自己并且边数不为1的祖先个数即为不同集合的数目

if (fa[i]==i && pt[i]==line[i]+1) ans++;

cout<<ans<<endl;

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: