hud 2473 Junk-Mail Filter

1.题目

http://acm.hdu.edu.cn/showproblem.php?pid=2473

2.分析

并查集删除点的做法:不是真正删除,而是将所有节点全部处理成非根节点,这样在做删除操作的时候,只用换一下根节点即表示删除了根节点。
如果在[0,N]中选择根节点,则不可避免的需要处理两种情况:删除非根节点;删除根节点;程序中如果直接建图添加这两种操作,则会导致TLE,因为数据量太大。
(自己做的时候用的就是直接建图添加考虑两种删除操作的思路,毫无疑问TLE)

参考网上的代码分析思路:将[0,N-1]中的所有点处理成并查集集合中的非根节点,这样在处理删除操作的时候只用换一下其对应的根节点即可,不用考虑删除该点之后会对其所处集合的影响(例如:删除非根节点怎么办?删除根节点怎么办?)    具体的处理过程为:初始化和合并的时候将[0,N-1]中的所有父节点处理成[N,2*N-1]中的节点;当需要删除节点的时候将其父节点修改为[2*N,3*N-1]中的点,保证[0,N-1] 都是集合中的非根节点。

3.复杂度

空间复杂度为O(N),建立一个集合的时间复杂度为O(1),N次合并M次查找的时间复杂度为O(MAlpha(N)),这里Alpha是Ackerman函数的某个反函数,在很大的范围内(人类目前观测到的宇宙范围估算有10的80次方个原子,这小于前面所说的范围)这个函数的值可以看成是不大于4的,所以并查集的操作可以看做是线性的。

4.涉及内容

数据结构:并查集

5.感想

如果碰到大数据题目发现超时,则可靠的做法是尽量不要存在遍历数据的操作,尽量用开辟大数组的方法来记录结果。(自己体会用空间换时间的思想,很深奥啊)

6.代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>

long f2473[1200005],N,M,top;
long a2473[100005];

void makeset2473()
{
	for(long i=0;i<N;++i)
		f2473[i]=i+N;
	for(long i=N;i<1200005;++i)
		f2473[i]=i;
}

long find2473(long x)
{
	return f2473[x]==x?f2473[x]:f2473[x]=find2473(f2473[x]);
}

void union2473(long r1,long r2)
{
	long a=find2473(r1);
	long b=find2473(r2);
	if(a==b) return ;
	f2473[a]=b;
}

int main()
{
	freopen("in.txt","r",stdin);
	long k=0,A,B;
	char op[5];;
	while(1)//将scanf写到while循环中不是一个好主意,总会发生不可思议的事情
    {
		scanf("%ld%ld",&N,&M);
		if(N==0&&M==0) break;
		top=N+N;
        makeset2473();
        for(int i=0;i<M;++i)
        {
            scanf("%s",&op);
            switch(op[0])
            {
				case 'M':{
					scanf("%ld%ld",&A,&B);
					union2473(A,B);
					}break;
				case 'S':{
					scanf("%ld",&A);
					f2473[A]=top++;
					}break;
            }
        }
		for(long i=0;i<N;++i)
			a2473[i]=find2473(i);
		std::sort(a2473,a2473+N);
        A=1;
		for ( long i = 1; i < N; ++ i )
			if ( a2473[i] != a2473[i-1] ) A ++;
		printf("Case #%d: %d\n",++k,A);
	}
	return 0;
}

7.参考文献

http://blog.csdn.net/xingyeyongheng/article/details/8823300 在处理合并和删除的时候就记录剩下的集合数量,其中的删除操作也是通过添加虚拟点实现,和下面的思路相同
{
将合并的数据(来自集合[0,N-1])看做最终数据数组A,B的索引。数组A用于并查集内部的操作,数组B用于索引查找真正的根节点,其中包含新添加的节点。
这样当删除节点x之后,x节点对应的新的虚拟节点存在数组B中,当后面有处理和x相关的合并操作的时候,可以直接在B中查到新的节点来操作。
这样能够正确处理程序的原因是:每次在执行union操作的时候参数用的都是B数组中的数据(b包含新增加节点的数据),从而保证能正确删除
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值