程序自动分析(并查集、离散化)

程序自动分析(并查集、离散化)

链接:https://ac.nowcoder.com/acm/problem/17881
来源:牛客网

时间限制:C/C++ 2秒,其他语言4秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld

题目描述

在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足。
考虑一个约束满足问题的简化版本:假设 𝑥1, 𝑥2, 𝑥3, ⋯ 代表程序中出现的变量,给定 𝑛 个形如 𝑥𝑖 = 𝑥𝑗 或 𝑥𝑖 ≠ 𝑥𝑗 的变量相等/不等的约束条件,请判定是否可以分别为每一个变量赋予恰当的值,使得上述所有约束条件同时被满足。例如,一个问题中的约束条件为: 𝑥1 = 𝑥2, 𝑥2 = 𝑥3, 𝑥3 = 𝑥4, 𝑥1 ≠ 𝑥4 ,这些约束条件显然是不可能同时被满足的,因此这个问题应判定为不可被满足。
现在给出一些约束满足问题,请分别对它们进行判定。

输入描述:

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

对于每个问题,包含若干行:
第1行包含1个正整数n,表示该问题中需要被满足的约束条件个数。
接下来n行,每行包括3个整数i,j,e,描述1个相等/不等的约束条件,相邻整数之间用单个空格隔开。若e=1,则该约束条件为xi=xj;若e=0,则该约束条件为xi≠xj。

输出描述:

包括t行。

第k行输出一个字符串“YES”或者“NO”(不包含引号,字母全部大写),“YES”表示输入中的第k个问题判定为可以被满足,“NO”表示不可被满足。

示例1

输入

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

输出

NO
YES

说明

在第一个问题中,约束条件为:x1=x2,x1≠x2。这两个约束条件互相矛盾,因此不可被同时满足。

在第二个问题中,约束条件为:x1=x2,x2=x1。这两个约束条件是等价的,可以被同时满足。

备注:

1≤n≤100000

1≤i,j≤1000000000

 

 

数据规模很大,下标到了1e9,开不下那么大的数组,所以要离散化

最简单的可以用unordered_map去代替原来的fa数组

 

 1 #include <bits/stdc++.h>
 2 typedef long long LL;
 3 #define pb push_back
 4 #define mst(a) memset(a,0,sizeof(a))
 5 const int INF = 0x3f3f3f3f;
 6 const double eps = 1e-8;
 7 const int mod = 1e9+7;
 8 const int maxn = 1e5+10;
 9 using namespace std;
10 
11 vector<pair<int,int> > vt;
12 unordered_map<int,int> fa;
13 int Find(int x)
14 {
15     return fa[x]==x? x:fa[x]=Find(fa[x]);
16 }
17 void Union(int x,int y)
18 {
19     int xx = Find(x), yy = Find(y);
20     if(xx!=yy) fa[xx] = yy;
21 }
22 
23 int main()
24 {
25     #ifdef DEBUG
26     freopen("sample.txt","r",stdin); //freopen("data.out", "w", stdout);
27     #endif
28     
29     int T;
30     scanf("%d",&T);
31     while(T--)
32     {
33         fa.clear(); vt.clear();
34         int n;
35         scanf("%d",&n);
36         for(int i=1;i<=n;i++)
37         {
38             int x,y,op;
39             scanf("%d %d %d",&x,&y,&op);
40             if(!fa[x]) fa[x] = x;
41             if(!fa[y]) fa[y] = y;
42             if(op==1) Union(x,y);
43             else vt.push_back({x,y}); 
44         }
45         int ok = 1;
46         for(auto it:vt)
47         {
48             if(Find(it.first)==Find(it.second))
49             {
50                 ok = 0;
51                 break;
52             }
53         }
54         printf(ok? "YES\n":"NO\n");
55     }
56     
57     return 0;
58 }

 

 

 

 

诈胡AC方法

from:https://blog.nowcoder.net/n/15516d835fc1475382f5d0e573ec9e53

对于1000000000数量级的i和j 我们将它,mod上一个较大,但是又没那么大的数。

比如mod上1e6+7 这样所有的i和j就强行缩小到我们可以接受的1e6 数量级了,再对这个范围进行并查集,应该就都没有问题了吧。

他的数据量 N 是小于100000的, 那你把所有的数mod完以后 很难出现重数的情况,就算出现wa的情况,你改改这个mod,依然有大概率可以AC的。

 

#include<iostream>
#include<algorithm>
#include<queue>
#include<string>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
#include<set>
#include<map>
#define ll long long
using namespace std;
#define close_stdin  ios::sync_with_stdio(false)
const int mod = 1e6 + 7;
int fa[1000007];
struct node {
    int x, y;
};
vector<node> vec;
//并查集常用操作 merge 与find
int find(int x) {  
    return(fa[x]==x?x:fa[x]=find(fa[x]));
}
void merge(int x, int y) { 
    fa[find(x)] = find(y);
}
void solve() {
    for (int i = 1;i <= mod;i++) {
        fa[i] = i;
    }
    int n;
    vector<node>vec;
    cin >> n;
    while (n--) {
        int i, j, e;
        cin >> i >> j >> e;
        i %= mod;j %= mod;
        if(!e){
            node temp;
            temp.x = i;temp.y = j;
            vec.push_back(temp);
        }
        else {
            merge(i, j);
        }
    }
    for (auto w : vec) {
        if (find(w.x) == find(w.y)) { cout << "NO\n";return; }
    }
    cout << "YES\n";
}
int main() {
    close_stdin;//只是为了让cin和printf一样快
    int T;
    cin >> T;
    while (T--) {
        solve();
    }
}
View Code

 

 

 

-

posted @ 2020-07-07 13:39  jiamian22  阅读(272)  评论(0)    收藏  举报