zoukankan      html  css  js  c++  java
  • hdu 2473 Junk-Mail Filter(并查集_虚节点)2008 Asia Regional Hangzhou

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

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

    题意——

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

    继续加油吧……

  • 相关阅读:
    数据结构之队列java版
    SPSS-相关性和回归分析(一元线性方程)案例解析(转)
    SPSS-非参数检验—两独立样本检验 案例解析(转)
    spss-非参数检验-K多个独立样本检验( Kruskal-Wallis检验)案例解析(转)
    SPSS-Friedman 秩和检验-非参数检验-K个相关样本检验 案例解析(转)
    SPSS-多重响应-频率和交叉表案例分析(问卷调查分析)(转)
    SPSS—回归—多元线性回归(转)
    SPSS—回归—曲线估计方程案例解析(转)
    SPSS—非线性回归(模型表达式)案例解析(转)
    SPSS—二元Logistic回归(转)
  • 原文地址:https://www.cnblogs.com/mypride/p/4687572.html
Copyright © 2011-2022 走看看