1. 程式人生 > 實用技巧 >【並查集】B001_AW_自動程式分析(不要求順序時的離散化)

【並查集】B001_AW_自動程式分析(不要求順序時的離散化)

考慮一個約束滿足問題的簡化版本:假設x1,x2,x3,…代表程式中出現的變數,給定n個形如xi=xj或xi≠xj的變數相等/不等的約束條件,請判定是否可以分別為每一個變數賦予恰當的值,使得上述所有約束條件同時被滿足。
例如,一個問題中的約束條件為:x1=x2,x2=x3,x3=x4,x1≠x4,這些約束條件顯然是不可能同時被滿足的,因此這個問題應判定為不可被滿足。
現在給出一些約束滿足問題,請分別對它們進行判定。
資料範圍
1≤n≤1000000
1≤i,j≤1000000000
輸入樣例:

2
2
1 2 1
1 2 0
2
1 2 1
2 1 1
輸出樣例:
NO
YES

方法一:離散化+並查集

x 最多會有 1e9 個,但 n 最大為 1e6,所以有 1e9-2e6 個數是可以不用的,故需要對資料進行離散化

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e6+5;
struct node{
    int u,v,e;
};
int id;
node A[N];
int fa[N];
unordered_map<int, int> m;
int get(int u) {
    if (m.find(u)==m.end()) m[u]=++id;
    return m[u];
}
int find(int u) {
    return fa[u]==u ? u : fa[u]=find(fa[u]);
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int t; cin>>t;
    while (t--) {
        int n,u,v,e; cin>>n;
        for (int i=0; i<n; i++) {
            cin>>u>>v>>e; 
            A[i]={get(u), get(v), e};
        }
        for (int i=1; i<=id; i++) fa[i]=i;
        for (int i=0; i<n; i++) if (A[i].e) {
            int fa_u=find(A[i].u), fa_v=find(A[i].v);
            if (fa_u != fa_v) {
                fa[fa_u]=fa_v;
            }
        }
        bool valid=true;
        for (int i=0; i<n; i++) if (!A[i].e) {
            int fa_u=find(A[i].u), fa_v=find(A[i].v);
            if (fa_u == fa_v) {
                valid=false;
                break;
            }
        }
        cout << (valid ?  "YES" : "NO") << '\n';
        m.clear();
    }
    return 0;
}

複雜度分析

  • Time\(O(nlogn)\)
  • Space\(O(n)\)