码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 2473 Junk-Mail Filter(并查集_虚节点)

时间:2015-07-29 22:57:25      阅读:219      评论:0      收藏:0      [点我收藏+]

标签:

感觉有些难的题,刚开始就想到了设立虚节点,但是实现总是出错,因为每次设立了虚节点之后,无法将原节点和虚节点分开,导致虚节点根本无意义。

以上纯属废话,可以忽略……

 

题意——

给定n个点(0, 1, 2, ..., n-1),可进行两种操作:1. 将两个点合并到一个集合中; 2. 将一个点从原有集合中取出。问最后点有几个集合。

很明显的并查集,包含合并,删除操作。

但是,删除某节点的时候,需要保证这个集合中,除了被删除节点的其它节点不变,这点有些难以处理。

我们知道,并查集其实是一棵棵树,我们将树中某节点删除,还要保证树的结构不变,可以采用一种方法,那就是“虚节点”,也就是说,我们并不删除那个节点,却将需要删除的节点中保存的数据转移到一个新的节点中,这个节点独立于这棵树之外。这样一来,我们查询那个节点的时候,会查询到新的节点,而原本的节点的作用仅仅是保持树的结构。

因此,我们需要两个数组,一个数组是fm[N+M],一个数组是fle[N],其中fle[]数组的fle[i]表示第i个节点的值,而fm[]数组中,fm[fle[i]]用来保存第i个节点的前驱,即fle[i]的父节点。

重点就在于这个fle[],每次删除节点i时,我们不改变fm[fle[i]],这样树的结构就不会变,而我们赋予fle[i]一个从未使用过的新值,就使实际上的i节点变化了。

这样每次删除i节点,都只需要赋予fle[i]一个从未用过的新值,类似于给i节点换一个新马甲,就可以解决问题。

我们可以从值为n开始,给节点赋的值依次为n++,这样,因为最多M次操作,那么最多换M个马甲,因此,fm的大小为M+N。

 

上代码——

技术分享
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 const int N = 100010;
 8 const int M = 1000010;
 9 
10 bool vis[N+M];
11 int fm[N+M], fle[N];
12 int n, m, a, b, pt, ans, tm;
13 char s[10];
14 
15 void init()
16 {
17     for(int i = 0; i < n; i++)
18     {
19         fm[i] = i;
20         fle[i] = i;
21     }
22     memset(vis, 0, sizeof(vis));
23     pt = n;
24     ans = 0;
25 }
26 
27 int mfind(int a)
28 {
29     int fa = a;
30 
31     while(fa != fm[fa]) fa = fm[fa];
32     while(a != fm[a])
33     {
34         int mid = fm[a];
35         fm[a] = fa;
36         a = mid;
37     }
38     return fa;
39 }
40 
41 void mmerge()
42 {
43     int fa = mfind(fm[fle[a]]);
44     int fb = mfind(fm[fle[b]]);
45     if(fa != fb) fm[fa] = fb;
46 }
47 
48 void dmerge()
49 {
50     fle[a] = pt;        //换马甲
51     fm[pt] = pt;        //给这个新值初始化父节点
52     pt++;               //为新马甲做准备
53 }
54 
55 void work()
56 {
57     while(m--)
58     {
59         scanf("%s", s);
60         if(s[0] == M)
61         {
62             scanf("%d%d", &a, &b);
63             mmerge();
64         }
65         else if(s[0] == S)
66         {
67             scanf("%d", &a);
68             dmerge();
69         }
70     }
71 
72     for(int i = 0; i < n; i++)
73     {
74         int ance = mfind(fle[i]);
75         if(!vis[ance])
76         {
77             ans++;
78             vis[ance] = 1;
79         }
80     }
81     printf("Case #%d: %d\n", tm++, ans);
82 }
83 
84 
85 
86 int main()
87 {
88     //freopen("test.in", "r", stdin);
89     tm = 1;
90     while(~scanf("%d%d", &n, &m) && (n+m))
91     {
92         init();
93         work();
94     }
95 }
View Code

 

 

ps: 这几天状态一直不好,但是今天突然看见一句话,感由心生,终于耐下心来弄明白了这道题——心若没有栖息的地方,在哪里都是流浪

继续加油吧……

hdu 2473 Junk-Mail Filter(并查集_虚节点)

标签:

原文地址:http://www.cnblogs.com/mypride/p/4687572.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!