hud 2473 Junk-Mail Filter

来源:互联网 发布:悟 无人机 知乎 编辑:程序博客网 时间:2024/05/23 07:22

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

原创粉丝点击