并查集

概念:

  并:合并两个元素所在的组

  查:查询两个元素是否属于同一个组

核心代码: 

 1 int par[MAX_N];        //父节点
 2 int rank[MAX_N];    //树的高度
 3 
 4 //初始化
 5 void init(int n)
 6 {
 7     for(int i = 0; i < n; i++)
 8     {
 9         par[i] = i;    //初始时一个树一个节点
10         rank[i] = 0;
11     }
12 }
13 
14 //查询树的根
15 int find(int x)
16 {
17     if(par[x] == x)
18     {
19         return x;
20     }
21     else
22     {
23         return par[x] = find(par[x]);    //递归 依次查询
24     }
25 }
26 
27 //合并x和y所属的集合
28 void unite(int x, int y)
29 {
30     x = find(x);    //x的根
31     y = find(y);    //y的根
32 
33     if(x == y)    //同一个根节点
34     {
35         return;
36     }
37     if(rank[x] < rank[y])        //从高度小的往高度大的合并
38     {
39         par[x] = y;
40     }
41     else
42     {
43         par[y] = x;
44         if(rank[x] == rank[y])    //相等 rank++
45             rank[x]++;
46     }
47 }
48 
49 //判断x和y是否同属于一个集合
50 int same(int x, int y)
51 {
52     return find(x) == find(y);
53 }

 

例题:

  题目链接:http://codeforces.com/gym/100989/problem/B

  题意:

    给定dp[]数组,它描述的是两个字符串a[]与b[]的关系情况。要求根据dp[]数组推出a[]与b[]。

    dp[]数组所描述关系:

 1 function LCS (A[1..R], B[1..C])
 2     DP = array(0..R, 0..C)
 3     for i := 0..R
 4        DP[i,0] = 0
 5     for j := 0..C
 6        DP[0,j] = 0
 7     for i := 1..R
 8         for j := 1..C
 9             if A[i] = B[j]
10                 DP[i,j] := DP[i-1,j-1] + 1
11             else
12                 DP[i,j] := max(DP[i,j-1], DP[i-1,j])
13     return DP[R,C]

  思路:

    并查集在这里的运用是,将a[]数组中与b[]数组中相等的元素合并在一棵树,再根据合并情况给两字符串赋值。

    val_trees[]将a[]与b[]中相同的合并在一棵树,然后依次小到大对不在一棵树上的a[]赋值,max_ch记录当前最

    大字符,然后再依次判断b[]中元素是否与a[]中的元素在一棵树上。是的话,把相等的那个字符赋值给它,不

    然就赋值为max_ch+1的那个字符(与a[]不存在相等关系的元素们可以是不同字符也可以是相同字符)。而且

    a[]中是允许有相同的元素的,比如a[1]=b[2]=a[3]之类的。

  代码:

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 const int MAXN = 32;
 6 
 7 int dp[MAXN][MAXN], val_trees[MAXN * 2];
 8 char a[MAXN], b[MAXN];
 9 
10 int root(int i)
11 {
12     return val_trees[i] == i ? i : val_trees[i] = root(val_trees[i]);
13 }
14 
15 int main(const int argc, const char *argv[])
16 {
17     int la, lb;
18     char max_ch = 'a';
19 
20     cin >> la >> lb;
21 
22     for (int i = 0; i < la + lb; i++)
23     {
24         val_trees[i] = i;
25     }
26 
27     for (int i = 0; i <= la; i++)
28         for (int j = 0; j <= lb; cin >> dp[i][j++]);
29 
30     for (int i = 0; i < la; i++)
31     {
32         for (int j = 0; j < lb; j++)
33         {
34             int dp_temp = dp[i + 1][j + 1];
35             if (dp_temp != dp[i][j + 1] && dp_temp != dp[i + 1][j])
36             {
37                 val_trees[root(la + j)] = root(i);
38             }
39         }
40     }
41 
42     for (int i = 0; i < la; i++)
43     {
44         if ((a[i] = root(i) + 'a') > max_ch)
45         {
46             max_ch = a[i];
47         }
48     }
49     max_ch++;
50 
51     for (int i = 0; i < lb; i++)
52     {
53         int ia = root(la + i);
54         b[i] = ia < la ? a[ia] : max_ch;
55     }
56 
57     cout << a << endl << b << endl;
58 
59     return 0;
60 }

 

转载于:https://www.cnblogs.com/friend-A/p/9293405.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值