UPC-星区划分(并查集+枚举)

简介: 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\n",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\n",ent);
    return 0;
}
//出自:Dili_iiii 

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

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

目录
相关文章
|
6月前
|
存储 人工智能 BI
【每日一题Day147】LC1615最大网络秩 | 枚举 哈希表
【每日一题Day147】LC1615最大网络秩 | 枚举 哈希表
50 0
|
6月前
|
Java
【每日一题Day121】LC1139最大的以 1 为边界的正方形 | 前缀和数组 + 枚举
【每日一题Day121】LC1139最大的以 1 为边界的正方形 | 前缀和数组 + 枚举
43 0
|
5月前
|
人工智能 C++
组合+排列 以及伯努利装错信封问题思路
这段代码是C++实现的一个程序,用于计算从`n`个不同元素中选择`m`个进行排列的组合总数(排列问题)。用户输入`n`和`m`,程序通过循环和条件判断生成所有可能的排列,并输出排列的总数。核心逻辑是使用回溯法,当找到一个满足条件(不包含重复元素)的排列时,更新计数器并继续寻找下一个排列。
44 0
|
5月前
|
移动开发 C++
【洛谷 P1157】组合的输出 题解(深度优先搜索+枚举子集)
该问题要求编程输出从1到n中选择r个元素的所有组合,组合按字典序排列。输入包含两自然数n和r(1&lt;n&lt;21, 0≤r≤n)。输出每个组合时,每个数字占据3个字符宽度。提供的AC代码使用C++,通过递归搜索方法枚举子集。样例输入为5 3,输出显示所有3个元素的组合。
46 0
|
6月前
|
机器学习/深度学习 算法 测试技术
【状态压缩 并集查找 图论】2157. 字符串分组
【状态压缩 并集查找 图论】2157. 字符串分组
【状态压缩 并集查找 图论】2157. 字符串分组
|
6月前
|
编译器 数据安全/隐私保护
PTA 线性表 7-1 约瑟夫环(Josephus)问题(by Yan) (100分) 按出列次序输出每个人的编号
PTA 线性表 7-1 约瑟夫环(Josephus)问题(by Yan) (100分) 按出列次序输出每个人的编号
|
6月前
|
算法 测试技术 C#
【图论 状态压缩 枚举】2959. 关闭分部的可行集合数目
【图论 状态压缩 枚举】2959. 关闭分部的可行集合数目
|
6月前
【每日一题Day311】LC1761一个图中连通三元组的最小度数 | 枚举
【每日一题Day311】LC1761一个图中连通三元组的最小度数 | 枚举
48 0
(枚举)(模拟)(前缀和)(数组模拟哈希)(可二分)1236. 递增三元组
(枚举)(模拟)(前缀和)(数组模拟哈希)(可二分)1236. 递增三元组
67 0
|
人工智能
UPC-魔法序列(结论+枚举)
UPC-魔法序列(结论+枚举)
84 0
UPC-魔法序列(结论+枚举)