PAT_甲级_1091 Acute Stroke

题目大意:

给定一个三维数组,数组元素的取值为0或者1,与某一元素相邻的元素是上下左右前后6个方向的元素,如果有若干个1相邻,那么就称这些1所组成的区域为一个块,如果块中1的个数不低于T个,那就称这个块为stroke core,现在要求计算所有stroke core的1个累计个数.

算法思路:

这里的块实际上和我们常见的图里面的连通分量的概念很相似,首先想到的就是遍历这个3维矩阵的每一个连通块,然后计算合法的每个连通块的1的个数(大于等于T),这里我们采用邻接矩阵存储这个3维图像,注意到一点,我们遍历中邻接点的位置为上下左右前后6个方向,那么我们就只需要每次往则6个方向前进一格就好,使用增量矩阵$incrementOfX$,$incrementOfY$,$incrementOfZ$对当前位置x,y,z进行加减获得下一个结点的位置.我们可以采用BFS的思想来进行处理(用DFS有可能会导致段错误),首先,每次选择进行BFS的起点都是没有入队并且为数字1的点,入队起点后,在BFS的搜索过程中,只要队列不空,出队队首节点,使用$count$统计当前连通块1的个数(队列中的节点都是数字为1的点),然后将6个领接方向的点中没有越界,数字为1并且没有加入队列的节点进行入队操作,循环结束时就返回$count$。最后使用$volumeOfStrokeCore$累计所有$count>=T$的$count$即可。

注意点:

  • 1、将多维数组写在main方法之外,可以自动赋初始值,节约时间,防止段错误。
  • 2、使用DFS会出现最后2个测试点段错误。

提交结果:

image.png

AC代码:

#include 
#include 

using namespace std;

struct Position{
    int x,y,z;
};

int image[1290][130][70];
bool isQueued[1290][130][70];// x,y,z位置的元素是否已经入队
int incrementOfX[6] = {0,0,0,0,1,-1};
int incrementOfY[6] = {0,0,1,-1,0,0};
int incrementOfZ[6] = {1,-1,0,0,0,0};
int M,N,L,T;// 长宽高和阈值

queue q;

// 判断x,y,z是否有必要访问
bool isQualified(int x,int y,int z){
    // 如果越界,则不再查询
    if(x>=M||x<0||y>=N||y<0||z>=L||z<0) return false;
    // 0不访问,已经入队的不访问
    return !(image[x][y][z] == 0 || isQueued[x][y][z]);
}

int BFS(int x,int y,int z){
    int count = 0;//当前连通块1的个数
    Position p{x,y,z};
    q.push(p);
    isQueued[x][y][z] = true;
    while (!q.empty()){
        // 队首元素出队
        p = q.front();
        q.pop();
        ++count;
        // 枚举6个方向的领接点
        for (int i = 0; i < 6; ++i) {
            int X = p.x+incrementOfX[i];
            int Y = p.y+incrementOfY[i];
            int Z = p.z+incrementOfZ[i];
            if(isQualified(X,Y,Z)){
                Position t{X,Y,Z};
                q.push(t);
                isQueued[X][Y][Z] = true;
            }
        }
    }
    return count;
}

int main()
{
    scanf("%d %d %d %d",&M,&N,&L,&T);
    for (int k = 0; k < L; ++k) {
        for (int i = 0; i < M; ++i) {
            for (int j = 0; j < N; ++j) {
                scanf("%d",&image[i][j][k]);
            }
        }
    }
    int volumeOfStrokeCore = 0;
    for (int k = 0; k < L; ++k) {
        for (int i = 0; i < M; ++i) {
            for (int j = 0; j < N; ++j) {
                // 遍历每一个元素
                if(image[i][j][k]==1&&!isQueued[i][j][k]){
                    // 只要当前元素为1,并且没有加入到队列之中
                    int countOne = BFS(i,j,k);//获得当前连通块中的个数
                    if(countOne>=T){
                        volumeOfStrokeCore += countOne;
                    }
                }
            }
        }
    }
    printf("%d",volumeOfStrokeCore);
    return 0;
}

你可能感兴趣的:(算法-数据结构,c++)