题解x1==x2

引用

并查集介绍

啰嗦

因为本题是newoj的一个比赛,所以暂时没有题目链接,后续的话管理员应该会放在oj上

题目描述

现在给定一些变量的等于或者不等于的约束,请你判断这些约束能否同时满足。
输入时变量为x1,x2,…,xn,均以x开始,x后面为该变量对应的编号。
约束条件只有"=“或者”!="。

样例
输入格式

输入第一行为正整数T,表示存在T组测试数据。
每组测试数据第一行为正整数n,表示约束条件的数量。
接下来n行,每行以下列形式输出

xi = xj
xi != xj

其中i和j表示对应变量的编号。

输出格式

对于每组测试数据,输出一行Yes表示可以满足,输出No表示不能满足。

数据范围

$ T \le 10 $
$ n \leq 1000000 $
$ 1 \leq i , j \leq 10^9 $

输入样例
2
4
x1 = x7
x9 != x7
x13 = x9
x1 = x13
2
x1 = x2
x2 = x1
输出样例
No
Yes

算法

(并查集) O ( l o g n ) O(logn) O(logn)

起初并没有想到用并查集的方法,只是用数组单纯地查询,但这肯定会超时的,数据范围太大了

用了并查集后,从题目的性质可以发现用unordered_map比较好,因为不单单是存映射关系(需要离散化,所以value不是存运算符右边的数),应该把值映射为下标,考虑到数据范围的原因,不用vector是因为需要在 $ O(1) $ 的时间复杂度返回指定元素的下标,才好在并查集中判断连通问题(这题也可以转换为判断连通问题,等号为连通,只需判断不等号左右两边的数是否都是同一个父节点)

时间复杂度
优化平均时间复杂度最坏时间复杂度
无优化 O ( l o g n ) O(logn) O(logn) O ( n ) O(n) O(n)
路径压缩 O ( α ( n ) ) O(\alpha(n)) O(α(n)) O ( l o g n ) O(logn) O(logn)
按秩合并 O ( l o g n ) O(logn) O(logn) O ( l o g n ) O(logn) O(logn)
路径压缩 + 按秩合并 O ( α ( n ) ) O(\alpha(n)) O(α(n)) O ( α ( n ) ) O(\alpha(n)) O(α(n))

C++ 代码

#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>

using namespace std;

const int N = 3e5 + 30;

typedef pair<string , string> PSS;

int p1[N]; //存储每个点的祖宗节点

int T , n , flag , idx;

string x1 , op , x2;

unordered_map<string , int> alls;
vector<PSS> e , ne; 

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

int main () {
    
    cin >> T;
    
    for (int i = 0; i < T; i ++) {
        
        cin >> n;
        idx = 1;
        flag = 0;
        alls.clear();
        e.clear();
        ne.clear();
        for(int j = 0; j < n; j ++) {
            cin >> x1 >> op >> x2;
            if(op == "=") e.push_back({x1 , x2});
            else ne.push_back({x1 , x2});
            if(!alls.count(x1)) alls[x1] = idx ++;
            if(!alls.count(x2)) alls[x2] = idx ++;
        }
        
        // 初始化,假定节点编号是1~n idx最后会多加1
        for (int k = 1; k < idx; k ++ ) p1[k] = k;
        
        for(int j = 0; j < e.size(); j ++)
            p1[find(alls[e[j].first])] = find(alls[e[j].second]);
            
        
        for(int j = 0; j < ne.size(); j ++) {
            if(find(alls[ne[j].first]) == find(alls[ne[j].second])) {
                flag = 1;
                break;
            }
        }
        
        if(flag) cout << "No" << endl;
        else cout << "Yes" << endl;
    }
    
    return 0;
}

过一半数据的代码

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>

using namespace std;

const int N = 1e9 + 10;

string x1 , op , x2;

int T , n , flag;

vector<pair<string , string>> x11 , x22;

int main(){
    
    cin >> T;
    
    for(int i = 0; i < T; i ++) {
        cin >> n;
        for(int j = 0; j < n; j ++) {
            cin >> x1 >> op >> x2;
            if(op == "=") x11.push_back({x1 , x2});
            else x22.push_back({x1 , x2});
        }
        
        sort(x11.begin() , x11.end());
        sort(x22.begin() , x22.end());
        x11.erase(unique(x11.begin() , x11.end()) , x11.end());
        x22.erase(unique(x22.begin() , x22.end()) , x22.end());
        for(int k = 0; k < x11.size(); k ++) {
            for(int l = 0; l < x22.size(); l ++) {
                if(x11[k].first == x22[l].first || x11[k].first == x22[l].second ||
                    x11[k].second == x22[l].first || x11[k].second == x22[l].second) {
                    flag = 1;
                    break;
                }
            }
            if(flag) break;
        }
        
        if(flag) cout << "No" << endl;
        else cout << "Yes" << endl;
        
        flag = 0;
        x11.clear();
        x22.clear();
    }
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值