You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

##AcWing 237. 程序自动分析

一、题目描述

在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足。

考虑一个约束满足问题的简化版本:假设 x_1,x_2,x_3,… 代表程序中出现的变量,给定 n 个形如 x_i=x_jx_i≠x_j 的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足。

例如,一个问题中的约束条件为:x_1=x_2x_2=x_3x_3=x_4x_1≠x_4,这些约束条件显然是不可能同时被满足的,因此这个问题应判定为不可被满足。

现在给出一些约束满足问题,请分别对它们进行判定。

输入格式 输入文件的第 1 行包含 1 个正整数 t,表示需要判定的问题个数,注意这些问题之间是相互独立的。

对于每个问题,包含若干行:

1 行包含 1 个正整数 n,表示该问题中需要被满足的约束条件个数。

接下来 n 行,每行包括 3 个整数 i,j,e,描述 1 个相等/不等的约束条件,相邻整数之间用单个空格隔开。若 e=1,则该约束条件为 x_i=x_j;若 e=0,则该约束条件为 x_i≠x_j

输出格式 输出文件包括 t 行。

输出文件的第 k 行输出一个字符串 YES 或者 NOYES 表示输入中的第 k 个问题判定为可以被满足,NO 表示不可被满足。

数据范围 1≤n≤10^5 1≤i,j≤10^9

输入样例

2
2
1 2 1
1 2 0
2
1 2 1
2 1 1

输出样例

NO
YES

二、题目解析

本题目主要是学习 离散化+二分+并查集,原因: 本题 1 <=i,j<=10^9,如果描述x_i,x_j也就是最大描述的是x_{1e9}

这样没法直接使用并查集,就像是桶没法开这么大!那怎么办才好呢?

输入的个数m比较小(<=10^5),可以使用离散化,然后通过二分的办法来定位一个大数在映射后数组的位置是多少。

三、静态数组+离散化+去重+并查集

#include <bits/stdc++.h>
using namespace std;
const int N = 200010; // 因为是需要存入左右两个条件xi=xj,这样最多是保存的两倍的n

int m;        // m个条件
int b[N], bl; // 离散化数组,数组长度
int p[N];     // 并查集数组
struct Node {
    int x, y, e;
} a[N]; // 输入的条件

// 并查集
int find(int x) {
    if (x == p[x]) return x;
    return p[x] = find(p[x]);
}

// 利用二分计算出x值在已排序数组b中的位置位置就是新的号码
int get(int x) {
    int l = 1, r = bl;
    while (l < r) {
        int mid = (l + r) >> 1;
        if (b[mid] < x)
            l = mid + 1;
        else
            r = mid;
    }
    return l;
}

int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        int flag = 0, idx = 0;
        scanf("%d", &m);

        for (int i = 1; i <= 2 * m; i++) p[i] = i;

        for (int i = 1; i <= m; i++) {
            scanf("%d %d %d", &a[i].x, &a[i].y, &a[i].e);
            b[idx++] = a[i].x, b[idx++] = a[i].y; // 存入离散化数组中,准备处理
        }

        // 静态数组离散化
        sort(b, b + 2 * m);
        bl = unique(b, b + 2 * m) - b;

        // 相等关系 <=> 同一个并查集
        for (int i = 1; i <= m; i++)
            if (a[i].e == 1) {
                int pa = find(get(a[i].x)), pb = find(get(a[i].y));
                if (pa != pb) p[pa] = pb;
            }

        // 不等关系 与 同一个并查集 存在冲突
        for (int i = 1; i <= m; i++)
            if (a[i].e == 0) {
                int pa = find(get(a[i].x)), pb = find(get(a[i].y));
                if (pa == pb) {
                    flag = 1;
                    break;
                }
            }

        if (flag)
            puts("NO");
        else
            puts("YES");
    }
    return 0;
}