其他分享
首页 > 其他分享> > Codeforces Round #812 (Div. 2) E(并查集)

Codeforces Round #812 (Div. 2) E(并查集)

作者:互联网

种类并查集:定义种类之间的关系来判断操作是否进行

题目大意:对于题目给出的一个矩阵,我们可以进行一种操作:swap(a[i][j],a[j][i])

使得矩阵可以变换为字典序最小的矩阵

 

思路:

  通过扫描整个矩阵,每次都判断a[i][j] 和 a[j][i]是否需要交换

  交换的前提就是: 对第i行/第j列操作,如果既对第 i 行又第 j 列进行操作等于没交换

  所以我们可以将 i 和 j定义为敌人,当 他们是敌人的时候,说明需要交换

  而他们是朋友的时候就说明无需交换

 

  这里就涉及到种类并查集了,我们定义一个2*n的数组,如果i 和 j 是敌人:

    merge( i , j+n );

    merge( i+n , j );

  这样在查询时如果find(i)>n说明i与另外一个元素有敌对关系,可以进行交换

  否则如果是朋友:

    merge( i , j );

    merge( i+n , j+n );

  find(i) <= n 说明他们为朋友关系,不可以交换 

 1 # include<iostream>
 2 # include<bits/stdc++.h>
 3 using namespace std;
 4 # define int long long
 5 # define endl "\n"
 6 const int N = 2e5 + 10;
 7 int a[1010][1010];
 8 int f[1010 << 1];
 9 vector<int> siz(1010 << 1);
10 int find(int x) {
11     if (f[x] == x) return x;
12     else return find(f[x]);
13 }
14 
15 void merge(int a, int b) {
16     int x = find(a);
17     int y = find(b);
18     if (x != y) {
19         if(siz[x]>siz[y]) swap(x,y);
20         f[x] = y;
21         siz[y] += siz[x];
22     }
23 }
24 void solve() {
25     int n;
26     cin >> n;
27     for (int i = 1; i <= n; ++i)
28         for (int j = 1; j <= n; ++j)
29             cin >> a[i][j];
30     for (int i = 1; i <= 2 * n; ++i) {
31         f[i] = i;
32         siz[i] = 1;
33     }
34     for (int i = 1; i <= n; ++i)
35         for (int j = i + 1; j <= n; ++j) {
36             if (a[i][j] > a[j][i]) {
37                 int x = find(i), y = find(j);
38                 if (x == y) continue;
39                 merge(i, j + n);
40                 merge(i + n, j);
41             } else if (a[i][j] < a[j][i]) {
42                 int x = find(i), y = find(j + n);
43                 if (x == y) continue;
44                 merge(i, j);
45                 merge(i + n, j + n);
46             }
47         }
48     for (int j = 1; j <= n; ++j) {
49         if (find(j) > n) continue;
50         for (int i = 1; i <= n; ++i) swap(a[i][j], a[j][i]);
51     }
52     for (int i = 1; i <= n; ++i) {
53         for (int j = 1; j <= n; ++j) {
54             cout << a[i][j] << " ";
55         }
56         cout << endl;
57     }
58 
59 }
60 int tt;
61 signed main() {
62     ios::sync_with_stdio(false);
63     cin.tie(0);
64     cout.tie(0);
65     cin >> tt;
66     while (tt--)solve();
67 
68 
69     return 0;
70 }
View Code 

需要注意的是,因为要求字典序最小,所以要求优先满足之前的关系,所以在每次维护关系的时候

需要先对之前的关系进行判断。

标签:int,siz,查集,交换,find,merge,812,1010,Div
来源: https://www.cnblogs.com/empty-y/p/16560182.html