zoukankan      html  css  js  c++  java
  • 洛谷P1955 [NOI2015]程序自动分析

    洛谷P1955 [NOI2015]程序自动分析

    博客图片

    题目链接

    洛谷P1955 程序自动分析

    题目概述

    存在(n)个变量(x_1,x_2,dots,x_n),给出这(n)个变量之间的(n)个约束条件(x_i = x_j or x_i eq x_j)判断这些是否可以同时满足,如果可以输出YES,否则输出NO.一组测试包含多个测试,输入的开始给出测试的个数,每个测试相互独立.变量之间的约束条件输入的格式为(iquad jquad e),如果(e = 1)说明(x_i = x_j),如果(e=0)说明(x_i eq x_j.)

    题目分析

    可以先根据相等的条件把相等的变量划分到一个集合中,然后逐一的判断每个不相等的条件,取出这两个变量(x_i,x_j)如果(x_i,x_j)属于同一个值相等的集合,那么这个约束条件不满足,可以直接输出NO,当所有的不相等的约束条件都满足时输出YES.

    并查集就是这样一种支持将元素按所属的集合进行分类,可以找到集合中任意一个元素所属的集合,核心操作是union_set(x,y)find_set(x).以每个集合的树高用于合并时的优化,和查询时采用路径压缩在找到元素所属集合的根节点后,把从根节点到这个元素结点路径上的所有结点的前驱改为根节点,从而在一次(O(log(n)))的时间福再度查询后,下一次可以以(O(1))的时间复杂度获得这个元素的集合的根节点.经过这样的union_setfind_set操作,最后得到的并查集的一个类似于这种形式:

    graph TD r((r)) a((a)) b((b)) dots((...)) k((k)) r---a r---b r---dots r---k

    注意:但是题目中对于(i,j)范围的限定是(1leq i,j leq 10^9),如果直接开一个(10^{10})的数组,外加一些其它的空间开销,是没法分配这样大的空间的,如果数组开的小,会有一个测试点出现RE,一个可行的方案是对输入的数据进行离散化处理,输入的数据最多有(2n)个,而(n)的范围是(1leq n leq 10^5),空间开销比较小,假设一组输入的约束条件是:

    10000 1999999 1
    199999 99999999 0
    92713821 23713324 1
    10000 23713324 0
    

    很明显这样的数据如果直接用数组下标映射,数组的开销非常大,但实际上输入的数据非常少,把输入的每一个变量存储起来,得到这样的一个序列:

    10000 1999999 199999 99999999 92713821 23713324 10000 23713324
    

    然后按升序进行排列去重,得到:

    10000 199999 1999999 23713324 92713821 99999999
    

    这样就建立了原来数据和现在数据在序列中下标的映射:

    [buf[0]=10000,buf[1]=199999,dots ]

    如果需要查询某个数(x)在上面的有序序列中,可以用STL标准库里面的lower_bound方法,返回值是区间([first,last))第一个不小于(x)的数在这个区间的位置,如果没有,那么返回(last),因为上面的序列是单调递增的,并且查询的(x)一定位于其中,所以最后得到的一定是数(x)(buf)中的位置.

    经过上面的序列化处理后,利用并查集的模板可以轻松方便的解决这个题目

    代码实现

    /*
     * @Author: Shuo Yang
     * @Date: 2020-08-01 08:08:32
     * @LastEditors: Shuo Yang
     * @LastEditTime: 2020-08-01 10:50:03
     * @FilePath: /Code/luogu/P1955.cpp
     */ 
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1e6+5;
    int s[N];
    int heights[N];
    int buf[N];
    
    //并查集模板
    
    void init_set(){
        memset(heights, 0,sizeof(heights));
        for(int i = 0;i < N; ++i)
            s[i] = i;
    }
    
    int find_set(int x){
        int r = x;
        while( s[r] != r){
            r = s[r];
        }
        int i = x;
        while( i != r){
            int j = s[i];
            s[i] = r;
            i = j;
        }
        return r;
    }
    
    
    void union_set(int x, int y){
        x = find_set(x);
        y = find_set(y);
        if( heights[x] == heights[y]){
            heights[x]++;
            s[y] = x;
        }else{
            if( heights[x] < heights[y])
                s[x] = y;
            else
                s[y] = x;
        }
    }
    
    //这道题实际处理的部分
    
    struct node{
        int a,b;
    };
    
    node equ[N];
    node nequ[N];
    int cnt = 0;
    
    int get_index(int x){
        return lower_bound(buf, buf+cnt, x) - buf;
    }
    
    void solve(int n, int m){
        init_set();
        for(int i = 0; i < n; ++i){
            union_set(get_index(equ[i].a), get_index(equ[i].b));
        }
        for(int i = 0; i < m; ++i){
            if(find_set(get_index(nequ[i].a)) == find_set(get_index(nequ[i].b))){
                cout<<"NO"<<endl;
                return;
            }
        }
        cout<<"YES"<<endl;
    }
    
    int main(int argc, const char** argv) {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
        cout.tie(nullptr);
        int t;
        cin>>t;
        while(t--){
            int k;
            cin>>k;
            int n = 0;
            int m = 0;
            cnt = 0;
            for(int i = 0; i < k; ++i){
                int a,b,f;
                cin>>a>>b>>f;
                if(f==1){
                    equ[n++] = {a,b};
                }else{
                    nequ[m++] = {a,b};
                }
                buf[cnt++] = a;
                buf[cnt++] = b;
            }
            //排序去重
            sort(buf, buf+cnt);
            cnt = unique(buf, buf+cnt)-buf;
            solve(n,m);
        }
        return 0;
    }
    
    

    其它

  • 相关阅读:
    JVM 的主要组成部分及其作用
    一天一个 Linux 命令(5):pwd命令
    算法-经典趣题-马踏棋盘(又称骑士周游)
    SAP HANA Schemas 和 HDI Containers
    如何手动下载并安装 Visual Studio Code 的 SAP Fiori tools
    一个最简单的 Github workflow 例子
    SAP UI5 初学者教程之七
    最近看的动漫和电影
    关于工作,干了这碗鸡汤
    啊啊啊啊啊啊
  • 原文地址:https://www.cnblogs.com/2018slgys/p/13414051.html
Copyright © 2011-2022 走看看