zoukankan      html  css  js  c++  java
  • UPC-星区划分(并查集+枚举)

    天空黑暗到一定程度,星辰就会熠熠生辉

    星区划分

    时间限制: 1 Sec 内存限制: 128 MB
    提交: 1056 解决: 237
    [状态] [提交] [命题人:外部导入]
    题目描述
    爱好天文的小七发明了一种太空分区方法,在这个方法中,宇宙里亮度相近的星星被划为同一个星区。空间中任意相邻或坐标相同的星星若亮度差不大于给定整数M,则这两个星星属于同一星区(两个星星可能会有相同的坐标)。

    现给你一个空间n个星星的三维坐标(x,y,z),和亮度值v,每个星星的上、下、左、右、前、后的六个相邻位置被认为是与其相邻的。请你计算一下该空间内的星区数量。

    输入
    第一行1个正整数n。n<=1000
    第二行 1个正整数m。m<=109
    第二行到第n+1行,每行四个正整数x,y,z,v。0<=x,y,z,v<=109
    输出
    一行正整数k,代表星区数量。

    样例输入 Copy
    5
    2
    1 1 1 2
    1 2 3 2
    1 2 2 5
    1 1 0 3
    1 0 1 3
    样例输出 Copy
    3
    思路:

    暴力枚举每个点,判断周围六个点以及本身是否能够与他构成一个星区,如果可以构成同一星区但不在同一星区,要合并。
    ( 比赛的时候思路到这里就卡了,身为一名数据结构选手竟然没想到用并查集来维护。)

    暴力枚举每一颗星星,然后搜索它的六个方向坐标和与自己相同坐标的亮度,亮度合
    法的话就用并查集把他们的祖先统一,最后统计一下祖先是自己的数量就是星区的数量。
    复杂度:1000 * 1000 * 7

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1e6+7;
    struct node{
        int x,y,z,v;
        int root;
    }a[maxn];
    int n,m;
    bool check(int i,int j){
        int x1=a[i].x,x2=a[j].x;
        int y1=a[i].y,y2=a[j].y;
        int z1=a[i].z,z2=a[j].z;
        int w1=a[i].v,w2=a[j].v;
        if(x1==x2+1&&y1==y2&&z1==z2||x1==x2-1&&y1==y2&&z1==z2||x1==x2&&y1==y2+1&&z1==z2||x1==x2&&y1==y2-1&&z1==z2||x1==x2&&y1==y2&&z1==z2+1||x1==x2&&y1==y2&&z1==z2-1||x1==x2&&y1==y2&&z1==z2)
            if(abs(w1-w2)<=m) return true;
        return false;
    }
    int Find(int x){
        if(x!=a[x].root) a[x].root=Find(a[x].root);
        return a[x].root;
    }
    void Union(int x,int y){
        x=Find(x),y=Find(y);
        if(x!=y){
            a[x].root=y;
        }
    }
    int main(){
       /// int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            scanf("%d%d%d%d",&a[i].x,&a[i].y, &a[i].z ,&a[i].v );
            a[i].root=i;
        }
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(i==j) continue;
                else
                    if(check(i,j)) Union(i,j);
        int res=0;
        for(int i=1;i<=n;i++)
            //cout<<a[i].root<<" ";
            if(a[i].root==i) res++;
        printf("%d
    ",res);
        return 0;
    }
    
    

    最后放一个类似的题叭,应该是未改过的题~
    题目描述
    天文学家Doctor博士发明了一种太空分区方法,在这个方法中,宇宙里亮度相近的区域被划为同一个星区。空间中相邻两区域若亮度差不大于给定整数M,则这两区域属于同一星区。现给你一个空间的三维坐标图,每个坐标整点表示一个区域,其值表示其亮度,而其上、下、左、右、前、后六个区域被认为是与其相邻的。请你计算一下该空间内的星区数量。

    输入
    第一行三个正整数x、y、z(x、y、z<=50),表示空间的长宽高。
    第二行一个整数M。
    接下来为一行,xyz个0~255的整数,按照空间坐标大小的顺序由小到大依次给出每个区域的亮度。
    说明:对于空间两点p1(x1,y1,z1)和p2(x2,y2,z2),p1<p2当且仅当(x1<x2)或者(x1=x2且y1<y2)或者(x1=x2且y1=y2且z1<z2)。

    输出
    一个整数,空间中的星区数量。
    这个直接dfs就可以,因为坐标都是连续的,而且数据范围也比较小。

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    int num[55][55][55];
    bool mp[55][55][55];
    int d;
    int n,m,h;
    int dx[]={0,0,-1,1,0,0};
    int dy[]={1,-1,0,0,0,0};
    int dz[]={0,0,0,0,1,-1};
    bool check(int x,int y,int z)
    {
        if(x<1||x>n||y<1||y>m||z<1||z>h)
            return 1;
        if(mp[x][y][z])
            return 1;
        return 0;
    }
    void dfs(int x,int y,int z,int p){
        mp[x][y][z]=true;
        for(int i=0; i<6; ++i){
            int next_x=x+dx[i];
            int next_y=y+dy[i];
            int next_z=z+dz[i];
            if(next_x>=1&&next_x<=n&&next_y>=1&&next_y<=m&&next_z>=1&&next_z<=h&&!mp[next_x][next_y][next_z]&&abs(num[next_x][next_y][next_z]-p)<=d)
            {
                dfs(next_x,next_y,next_z,num[next_x][next_y][next_z]);
            }
        }
    }
    int main(){
       scanf("%d%d%d%d",&n,&m,&h,&d);
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                for(int k=1;k<=h;++k){
                    scanf("%d",&num[i][j][k]);
                }
            }
        }
        int ent=0;
        for(int i=1;i<=n;++i){
            for(int j=1;j<=m;++j){
                for(int k=1;k<=h;++k){
                    if(!mp[i][j][k]){
                        ent++;
                        dfs(i,j,k,num[i][j][k]);
                    }
                }
            }
        }
        printf("%d
    ",ent);
        return 0;
    }
    //出自:Dili_iiii 
    

    参考博客:【dfs模板】dfs找联通块分区 - Dili_iiii - 博客园

    其实这场比赛打的挺自闭的,好几个人讨论这个题也没想到并查集,最后想到的时候不想写了。但是真的嘴上说着不想打了,却还是满腔热血的去vj拉题,这也许就是acm的魅力所在吧。

  • 相关阅读:
    android手机rootROM下载地址
    mysql alter 语句用法,添加、修改、删除字段等
    java比较两个日期大小
    eclipse设置全局编码为UTF-8的方法
    Spring MVC 异步处理请求,提高程序性能
    ELK(ElasticSearch, Logstash, Kibana)搭建实时日志分析平台
    maven之发布项目到nexus【clean deploy命令】
    nexus-3本地下载jar的settipng.xml配置
    windows开启3306端口并用可视化工具访问远程mysql(授权访问)
    mysql 列转行,合并字段
  • 原文地址:https://www.cnblogs.com/OvOq/p/14853188.html
Copyright © 2011-2022 走看看