题目链接
该题本质就是遍历连通分支的问题,只不过是将二维矩阵拓展到三维矩阵,做法类似,算法思想可以看我的另一篇文章。
求矩阵的连通分支数问题
不过本题遍历连通块不能用DFS算法,因为最后两个样例连通块太深,递归的系统栈达到上限,从而爆栈,故最好用BFS算法,缺点就是要建队列,代码不够简洁。
AC Code:
#include<cstdio>
#include<queue>
using namespace std;
int m,n,l,T,ans=0;//m为行,n为列,l为层,ans为最后的输出数
int matrix[60][1286][128],inq[60][1286][128]={0};
//matrix为三维的0,1矩阵,第一维是层,后两维是行列,也可把层放在第三维
//inq判断该位置是否入过队列的三维数组,inq[z][x][y]=1表示第z层的第x行第y列元素已经入过队列了
struct node{//位置坐标
int x,y,z;
}Node;
int X[8]={1,-1,0,0,0,0},Y[8]={0,0,1,-1,0,0},Z[8]={0,0,0,0,1,-1};
//三维增量数组,用于查询相邻位
bool judge(int x,int y,int z){//判断该位是否应该入队列
if(x<0||x>=m||y<0||y>=n||z<0||z>=l) return false;
//超界,返回false
if(matrix[z][x][y]==0||inq[z][x][y]==1) return false;
//该位为0或已经入过队列了,返回false
return true;
//以上均不满足,返回true
}
void BFS(int x,int y,int z){
queue<node> q;//初始化队列
int cnt=0;//记录当前块中1的个数
Node.x=x;Node.y=y;Node.z=z;//为结点赋坐标值
q.push(Node);//结点入队列
inq[z][x][y]=1;//标记已入队列
while(!q.empty()){
node top=q.front();//取队首元素
q.pop();//队首元素出队列
cnt++;//当前块1个数加1
for(int i=0;i<6;i++){//循环6次,得到6个增量方向
int newx=top.x+X[i];
int newy=top.y+Y[i];
int newz=top.z+Z[i];
if(judge(newx,newy,newz)){//如果新的位置未入过队
Node.x=newx;Node.y=newy;Node.z=newz;
q.push(Node);//将结点入队
inq[newz][newx][newy]=1;//标记该位置已经入过队
}
}
}
if(cnt>=T) ans+=cnt;//当前块1个数超过阈值,要累加到最终结果内
}
int main(){
scanf("%d%d%d%d",&m,&n,&l,&T);
for(int z=0;z<l;z++){//注意层数循环在最外面
for(int x=0;x<m;x++){//行循环
for(int y=0;y<n;y++){//列循环
scanf("%d",&matrix[z][x][y]);
}
}
}
for(int z=0;z<l;z++){
for(int x=0;x<m;x++){
for(int y=0;y<n;y++){
if(matrix[z][x][y]==1&&inq[z][x][y]==0){
//该位为1且未如果队列,说明找到新块
BFS(x,y,z);//遍历新块,计算1的个数并标记值1的位为已入队
}
}
}
}
printf("%d",ans);//输出最终结果
return 0;
}