一道数据结构题 想了很久 并查集?

时间:2022-10-27 10:30:20
Description
有n个独立的磁铁(1,2,⋯n标号)放在桌上,一个人对这n堆进行移动操作,然后另一个人询问。

有以下规则:

M X Y : 将含有编号X的磁铁块放在包含Y的磁铁块的顶端。(磁铁块指很多磁铁吸在了一起)

C X : 询问在编号X磁铁下的磁铁的数目。

Input Format
第1行一个整数,操作数p。

第2行到第p+1行:每一行是个合法操作,形如M X Y或C X。

Output Format
对于每个C操作输出一行,即对应的磁铁数。

Sample Input
6
M 1 6
C 1
M 2 4
M 2 6
C 3
C 4

Sample Output
1
0
2

About Test Data
对于全部数据:1≤n≤30000;1≤p≤100000
对于50%的数据: 1≤n≤1000;1≤p≤10000


就是这样一道题目,请问该怎么做呢?并查集?

十分感谢大家!

7 个解决方案

#1


方法一:数据分为两部分,磁铁数组和磁铁组表。
磁铁数组包含所有磁铁信息,磁铁信息中有磁铁组号(或指针)、该铁在组中的位置(就是其下有多少磁铁。
磁铁组是个线性表,元素是磁铁号,只要求遍历、添加、合并功能,用链表实现。
初始化:所有磁铁,位置为0;为所有磁铁创建单元磁铁组表。
M命令:找到X所在磁铁组GX、,O(1)操作;
       找到Y所在磁铁组GY,O(1)操作;
       遍历GX中的元素,将对应磁铁信息中的磁铁组号(或指针)改为GY,位置加上Length(GY),O(N)操作
                 GY合并到GX中,O(1)操作。
       
C命令:输出X中的位置信息

初始化时可以不创建磁铁组表,这样就要在M命令中进行判断,分别对GX和GY为空时进行处理

#2


方法二:
磁铁信息使用链接信息,同组磁铁组成链表,需要能够通过任一元素找到链表首尾,可以使用双向链,或者使用带头标志的循环链。下面用双向链为例:
初始化:所有磁铁prev=null,next=null
M命令:
      找到Y所在链表首HY,O(N)
      找到X所在链表尾TX,O(N)
      连接两个链表,O(N)
C命令:
      找到从X遍历到链表尾并计数,O(N)

可以在磁铁信息中保存“其下磁铁数”的信息以加快C命令:
    在M命令的第一步时,可以计算出Y链表的长度(Y中的位置信息+遍历过的节点数)
    在M命令的第二步时,先找到X所在链表首,再遍历到链表尾,所有节点的位置信息+Y链表长度

#3


并查集无误。合并的时候多做几步操作就是。

1L 2L的办法总复杂度都会退化到平方的。数据很好构造。

#4


引用 3 楼 FancyMouse 的回复:
并查集无误。合并的时候多做几步操作就是。

1L 2L的办法总复杂度都会退化到平方的。数据很好构造。


什么情况下会退化到平方?能举个例子吗?

空间效率确实不高。

#5


引用 3 楼 FancyMouse 的回复:
并查集无误。合并的时候多做几步操作就是。

1L 2L的办法总复杂度都会退化到平方的。数据很好构造。


还请问c++stl中有并查集的库么?

#6


仅供参考
#include <algorithm>
#include <iostream>
#include <functional>
#include <cstring>
using namespace std;
int main() {
    char *Alphabet = "abcdefghijklmnopqrstuvwxyz" ;
    char *Vowels   = "aeiou" ;
    char *AlphaNum = "0123456789abcdef" ;
    char result[45] ;
    char *last ;

    int lenA  = strlen(Alphabet) ;
    int lenV  = strlen(Vowels  ) ;
    int lenAN = strlen(AlphaNum) ;

    cout << "Alphabet = " << Alphabet << endl ;
    cout << "Vowels   = " << Vowels   << endl ;
    cout << "AlphaNum = " << AlphaNum << endl ;

    cout << "\nusing non-predicate versions" << endl ;

    //non-predicate set_difference
    last = set_difference(Alphabet, Alphabet+lenA,
                          AlphaNum, AlphaNum+lenAN,
                          result) ;
    *last = 0 ;
    cout << "set_difference(Alphabet, AlphaNum) =  " << result << endl ;

    //non-predicate set_intersection
    last = set_intersection(Alphabet, Alphabet+lenA,
                            AlphaNum, AlphaNum+lenAN,
                            result) ;
    *last = 0 ;
    cout << "set_intersection(Alphabet, AlphaNum) =  " << result << endl ;

    //non-predicate set_symmetric_difference
    last = set_symmetric_difference(Alphabet, Alphabet+lenA,
                                    Vowels  , Vowels  +lenV,
                                    result) ;
    *last = 0 ;
    cout << "set_symmetric_difference(Alphabet, Vowels) =  " << result << endl ;

    //non-predicate set_union
    last = set_union(Alphabet, Alphabet+lenA,
                     AlphaNum, AlphaNum+lenAN,
                     result) ;
    *last = 0 ;
    cout << "set_union(Alphabet, AlphaNum) =  " << result << endl ;

    cout << "\nusing predicate versions" << endl ;

    //predicate set_difference
    last = set_difference(Alphabet, Alphabet+lenA,
                          AlphaNum, AlphaNum+lenAN,
                          result  , less<char>()) ;
    *last = 0 ;
    cout << "set_difference(Alphabet, AlphaNum) =  " << result << endl ;

    //predicate set_intersection
    last = set_intersection(Alphabet, Alphabet+lenA,
                            AlphaNum, AlphaNum+lenAN,
                            result  , less<char>()) ;
    *last = 0 ;
    cout << "set_intersection(Alphabet, AlphaNum) =  " << result << endl ;

    //predicate set_symmetric_difference
    last = set_symmetric_difference(Alphabet, Alphabet+lenA,
                                    Vowels  , Vowels  +lenV,
                                    result  , less<char>()) ;
    *last = 0 ;
    cout << "set_symmetric_difference(Alphabet, Vowels) =  " << result << endl ;

    //predicate set_union
    last = set_union(Alphabet, Alphabet+lenA,
                     AlphaNum, AlphaNum+lenAN,
                     result  , less<char>()) ;
    *last = 0 ;
    cout << "set_union(Alphabet, AlphaNum) =  " << result << endl ;

    return 0 ;
}

#7


引用 6 楼 zhao4zhong1 的回复:
仅供参考
#include <algorithm>
#include <iostream>
#include <functional>
#include <cstring>
using namespace std;
int main() {
    char *Alphabet = "abcdefghijklmnopqrstuvwxyz" ;
    char *Vowels   = "aeiou" ;
    char *AlphaNum = "0123456789abcdef" ;
    char result[45] ;
    char *last ;

    int lenA  = strlen(Alphabet) ;
    int lenV  = strlen(Vowels  ) ;
    int lenAN = strlen(AlphaNum) ;

    cout << "Alphabet = " << Alphabet << endl ;
    cout << "Vowels   = " << Vowels   << endl ;
    cout << "AlphaNum = " << AlphaNum << endl ;

    cout << "\nusing non-predicate versions" << endl ;

    //non-predicate set_difference
    last = set_difference(Alphabet, Alphabet+lenA,
                          AlphaNum, AlphaNum+lenAN,
                          result) ;
    *last = 0 ;
    cout << "set_difference(Alphabet, AlphaNum) =  " << result << endl ;

    //non-predicate set_intersection
    last = set_intersection(Alphabet, Alphabet+lenA,
                            AlphaNum, AlphaNum+lenAN,
                            result) ;
    *last = 0 ;
    cout << "set_intersection(Alphabet, AlphaNum) =  " << result << endl ;

    //non-predicate set_symmetric_difference
    last = set_symmetric_difference(Alphabet, Alphabet+lenA,
                                    Vowels  , Vowels  +lenV,
                                    result) ;
    *last = 0 ;
    cout << "set_symmetric_difference(Alphabet, Vowels) =  " << result << endl ;

    //non-predicate set_union
    last = set_union(Alphabet, Alphabet+lenA,
                     AlphaNum, AlphaNum+lenAN,
                     result) ;
    *last = 0 ;
    cout << "set_union(Alphabet, AlphaNum) =  " << result << endl ;

    cout << "\nusing predicate versions" << endl ;

    //predicate set_difference
    last = set_difference(Alphabet, Alphabet+lenA,
                          AlphaNum, AlphaNum+lenAN,
                          result  , less<char>()) ;
    *last = 0 ;
    cout << "set_difference(Alphabet, AlphaNum) =  " << result << endl ;

    //predicate set_intersection
    last = set_intersection(Alphabet, Alphabet+lenA,
                            AlphaNum, AlphaNum+lenAN,
                            result  , less<char>()) ;
    *last = 0 ;
    cout << "set_intersection(Alphabet, AlphaNum) =  " << result << endl ;

    //predicate set_symmetric_difference
    last = set_symmetric_difference(Alphabet, Alphabet+lenA,
                                    Vowels  , Vowels  +lenV,
                                    result  , less<char>()) ;
    *last = 0 ;
    cout << "set_symmetric_difference(Alphabet, Vowels) =  " << result << endl ;

    //predicate set_union
    last = set_union(Alphabet, Alphabet+lenA,
                     AlphaNum, AlphaNum+lenAN,
                     result  , less<char>()) ;
    *last = 0 ;
    cout << "set_union(Alphabet, AlphaNum) =  " << result << endl ;

    return 0 ;
}


我去研究一下!

#1


方法一:数据分为两部分,磁铁数组和磁铁组表。
磁铁数组包含所有磁铁信息,磁铁信息中有磁铁组号(或指针)、该铁在组中的位置(就是其下有多少磁铁。
磁铁组是个线性表,元素是磁铁号,只要求遍历、添加、合并功能,用链表实现。
初始化:所有磁铁,位置为0;为所有磁铁创建单元磁铁组表。
M命令:找到X所在磁铁组GX、,O(1)操作;
       找到Y所在磁铁组GY,O(1)操作;
       遍历GX中的元素,将对应磁铁信息中的磁铁组号(或指针)改为GY,位置加上Length(GY),O(N)操作
                 GY合并到GX中,O(1)操作。
       
C命令:输出X中的位置信息

初始化时可以不创建磁铁组表,这样就要在M命令中进行判断,分别对GX和GY为空时进行处理

#2


方法二:
磁铁信息使用链接信息,同组磁铁组成链表,需要能够通过任一元素找到链表首尾,可以使用双向链,或者使用带头标志的循环链。下面用双向链为例:
初始化:所有磁铁prev=null,next=null
M命令:
      找到Y所在链表首HY,O(N)
      找到X所在链表尾TX,O(N)
      连接两个链表,O(N)
C命令:
      找到从X遍历到链表尾并计数,O(N)

可以在磁铁信息中保存“其下磁铁数”的信息以加快C命令:
    在M命令的第一步时,可以计算出Y链表的长度(Y中的位置信息+遍历过的节点数)
    在M命令的第二步时,先找到X所在链表首,再遍历到链表尾,所有节点的位置信息+Y链表长度

#3


并查集无误。合并的时候多做几步操作就是。

1L 2L的办法总复杂度都会退化到平方的。数据很好构造。

#4


引用 3 楼 FancyMouse 的回复:
并查集无误。合并的时候多做几步操作就是。

1L 2L的办法总复杂度都会退化到平方的。数据很好构造。


什么情况下会退化到平方?能举个例子吗?

空间效率确实不高。

#5


引用 3 楼 FancyMouse 的回复:
并查集无误。合并的时候多做几步操作就是。

1L 2L的办法总复杂度都会退化到平方的。数据很好构造。


还请问c++stl中有并查集的库么?

#6


仅供参考
#include <algorithm>
#include <iostream>
#include <functional>
#include <cstring>
using namespace std;
int main() {
    char *Alphabet = "abcdefghijklmnopqrstuvwxyz" ;
    char *Vowels   = "aeiou" ;
    char *AlphaNum = "0123456789abcdef" ;
    char result[45] ;
    char *last ;

    int lenA  = strlen(Alphabet) ;
    int lenV  = strlen(Vowels  ) ;
    int lenAN = strlen(AlphaNum) ;

    cout << "Alphabet = " << Alphabet << endl ;
    cout << "Vowels   = " << Vowels   << endl ;
    cout << "AlphaNum = " << AlphaNum << endl ;

    cout << "\nusing non-predicate versions" << endl ;

    //non-predicate set_difference
    last = set_difference(Alphabet, Alphabet+lenA,
                          AlphaNum, AlphaNum+lenAN,
                          result) ;
    *last = 0 ;
    cout << "set_difference(Alphabet, AlphaNum) =  " << result << endl ;

    //non-predicate set_intersection
    last = set_intersection(Alphabet, Alphabet+lenA,
                            AlphaNum, AlphaNum+lenAN,
                            result) ;
    *last = 0 ;
    cout << "set_intersection(Alphabet, AlphaNum) =  " << result << endl ;

    //non-predicate set_symmetric_difference
    last = set_symmetric_difference(Alphabet, Alphabet+lenA,
                                    Vowels  , Vowels  +lenV,
                                    result) ;
    *last = 0 ;
    cout << "set_symmetric_difference(Alphabet, Vowels) =  " << result << endl ;

    //non-predicate set_union
    last = set_union(Alphabet, Alphabet+lenA,
                     AlphaNum, AlphaNum+lenAN,
                     result) ;
    *last = 0 ;
    cout << "set_union(Alphabet, AlphaNum) =  " << result << endl ;

    cout << "\nusing predicate versions" << endl ;

    //predicate set_difference
    last = set_difference(Alphabet, Alphabet+lenA,
                          AlphaNum, AlphaNum+lenAN,
                          result  , less<char>()) ;
    *last = 0 ;
    cout << "set_difference(Alphabet, AlphaNum) =  " << result << endl ;

    //predicate set_intersection
    last = set_intersection(Alphabet, Alphabet+lenA,
                            AlphaNum, AlphaNum+lenAN,
                            result  , less<char>()) ;
    *last = 0 ;
    cout << "set_intersection(Alphabet, AlphaNum) =  " << result << endl ;

    //predicate set_symmetric_difference
    last = set_symmetric_difference(Alphabet, Alphabet+lenA,
                                    Vowels  , Vowels  +lenV,
                                    result  , less<char>()) ;
    *last = 0 ;
    cout << "set_symmetric_difference(Alphabet, Vowels) =  " << result << endl ;

    //predicate set_union
    last = set_union(Alphabet, Alphabet+lenA,
                     AlphaNum, AlphaNum+lenAN,
                     result  , less<char>()) ;
    *last = 0 ;
    cout << "set_union(Alphabet, AlphaNum) =  " << result << endl ;

    return 0 ;
}

#7


引用 6 楼 zhao4zhong1 的回复:
仅供参考
#include <algorithm>
#include <iostream>
#include <functional>
#include <cstring>
using namespace std;
int main() {
    char *Alphabet = "abcdefghijklmnopqrstuvwxyz" ;
    char *Vowels   = "aeiou" ;
    char *AlphaNum = "0123456789abcdef" ;
    char result[45] ;
    char *last ;

    int lenA  = strlen(Alphabet) ;
    int lenV  = strlen(Vowels  ) ;
    int lenAN = strlen(AlphaNum) ;

    cout << "Alphabet = " << Alphabet << endl ;
    cout << "Vowels   = " << Vowels   << endl ;
    cout << "AlphaNum = " << AlphaNum << endl ;

    cout << "\nusing non-predicate versions" << endl ;

    //non-predicate set_difference
    last = set_difference(Alphabet, Alphabet+lenA,
                          AlphaNum, AlphaNum+lenAN,
                          result) ;
    *last = 0 ;
    cout << "set_difference(Alphabet, AlphaNum) =  " << result << endl ;

    //non-predicate set_intersection
    last = set_intersection(Alphabet, Alphabet+lenA,
                            AlphaNum, AlphaNum+lenAN,
                            result) ;
    *last = 0 ;
    cout << "set_intersection(Alphabet, AlphaNum) =  " << result << endl ;

    //non-predicate set_symmetric_difference
    last = set_symmetric_difference(Alphabet, Alphabet+lenA,
                                    Vowels  , Vowels  +lenV,
                                    result) ;
    *last = 0 ;
    cout << "set_symmetric_difference(Alphabet, Vowels) =  " << result << endl ;

    //non-predicate set_union
    last = set_union(Alphabet, Alphabet+lenA,
                     AlphaNum, AlphaNum+lenAN,
                     result) ;
    *last = 0 ;
    cout << "set_union(Alphabet, AlphaNum) =  " << result << endl ;

    cout << "\nusing predicate versions" << endl ;

    //predicate set_difference
    last = set_difference(Alphabet, Alphabet+lenA,
                          AlphaNum, AlphaNum+lenAN,
                          result  , less<char>()) ;
    *last = 0 ;
    cout << "set_difference(Alphabet, AlphaNum) =  " << result << endl ;

    //predicate set_intersection
    last = set_intersection(Alphabet, Alphabet+lenA,
                            AlphaNum, AlphaNum+lenAN,
                            result  , less<char>()) ;
    *last = 0 ;
    cout << "set_intersection(Alphabet, AlphaNum) =  " << result << endl ;

    //predicate set_symmetric_difference
    last = set_symmetric_difference(Alphabet, Alphabet+lenA,
                                    Vowels  , Vowels  +lenV,
                                    result  , less<char>()) ;
    *last = 0 ;
    cout << "set_symmetric_difference(Alphabet, Vowels) =  " << result << endl ;

    //predicate set_union
    last = set_union(Alphabet, Alphabet+lenA,
                     AlphaNum, AlphaNum+lenAN,
                     result  , less<char>()) ;
    *last = 0 ;
    cout << "set_union(Alphabet, AlphaNum) =  " << result << endl ;

    return 0 ;
}


我去研究一下!