算法竞赛进阶指南---0x41 (并查集) 程序自动分析

题面

算法竞赛进阶指南---0x41 (并查集) 程序自动分析_第1张图片
算法竞赛进阶指南---0x41 (并查集) 程序自动分析_第2张图片
算法竞赛进阶指南---0x41 (并查集) 程序自动分析_第3张图片

题解

  1. 很明显的并查集,并查集是将有关联的(相等,连通,吃与被吃)元素放入到一个集合中进行维护(集合大小,到祖宗节点的距离),之后对集合或集合之间的关系进行询问。
  2. 我们可以发现约束条件的顺序不影响最后的结果,因此我们可以先将所有相等的约束条件放入集合中维护(合并),然后再判断不相等的约束条件是否在一个集合中,如果在一个集合中,就矛盾,因为在一个集合中表示的是相同的约束条件。
  3. 看本题的数据范围,数据范围最大达到1e9 ,而个数只达到1e6,所以要进行离散化之后,再放入集合中维护

代码

#include

using namespace std;
const int N = 2e6 + 10;

int t, n;
int p[N];
int cnt;
unordered_map<int, int> mp;

struct Node {
    int x, y, e;
} node[N];

//不饱序离散化操作
int get(int x) {
    if (mp.count(x) == 0) mp[x] = ++cnt;
    return mp[x];
}

//返回x的祖宗节点
int find(int x) {
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}


int main() {

    cin >> t;
    while (t--) {
        mp.clear();
        cnt=0;
        cin >> n;

        for (int i = 1; i <= n; i++) {
            int e, x, y;
            cin >> x >> y >> e;
            node[i] = {get(x), get(y), e};
        }
        //初始化数组(注意初始化数组的大小,我就wa在了这里)
        for (int i = 1; i <=cnt ; i++) p[i] = i;

        //先进行相同的条件合并
        for (int i = 1; i <= n; i++) {
            if (node[i].e == 1) {
                int px = find(node[i].x);
                int py = find(node[i].y);
                p[px] = py;
            }
        }

        //然后进行不同的条件验证
        bool flag = true;
        for (int i = 1; i <= n; i++) {
            if (node[i].e == 0) {
                int px = find(node[i].x);
                int py = find(node[i].y);
                if (px == py) {
                    flag = false;
                    break;
                }
            }
        }

        if (flag) {
            cout << "YES" << endl;
        } else {
            cout << "NO" << endl;
        }
    }


    return 0;
}

你可能感兴趣的:(#,并查集,算法,数据结构,并查集)