我的PAT-ADVANCED代码仓:https://github.com/617076674/PAT-ADVANCED
原题链接:https://pintia.cn/problem-sets/994805342720868352/problems/994805375457411072
题目描述:
题目翻译:
1091 急性中风
确定急性脑卒中的一个重要依据是脑卒中核心的体积。给定图像分析的结果,其中在每个MRI切片中识别核心区域,你的工作是计算中风核心的体积。
输入格式:
每个输入文件包含一个测试用例。在每个测试用例中,第一行给出4个正整数:M、N、L和T,其中M和N是每个切片的尺寸(切片的像素在M×N矩阵中,最大分辨率为1286 × 128);L(<= 60)是一个大脑的切片总数;T是判定界限(如果连接核心的容量小于T,则不得计算该核心)。
接下来给出L个脑切片。每个切片由0和1组成的M × N矩阵表示,其中1表示中风区域,0表示正常区域。 由于切片的厚度是常数,我们只需计算1的数量即可获得体积。 然而,大脑中可能存在几个分离的核心区域,并且仅计算其体积不小于T的核心区域。 如果它们共享公共侧,则连接两个像素并因此属于相同区域,如图1所示,其中所有6个红色像素连接到蓝色像素。
输出格式:
对每个测试用例,在一行中输出中风区域的总体积。
输入样例:
3 4 5 2
1 1 1 1
1 1 1 1
1 1 1 1
0 0 1 1
0 0 1 1
0 0 1 1
1 0 1 1
0 1 0 0
0 0 0 0
1 0 1 1
0 0 0 0
0 0 0 0
0 0 0 1
0 0 0 1
1 0 0 0
输出样例:
26
知识点:深度优先遍历、广度优先遍历
思路一:深度优先遍历(测试点4和5会爆系统栈引发段错误)
三维深度优先遍历,用一个二维数组int directions[3][6]来定义6个方向。
时间复杂度极高,可能达到O(6 ^ (M * N * L))。空间复杂度是O(M * N * L)。
C++代码:
#include<iostream>
using namespace std;
int M, N, L, T;
int brain[1286][128][60];
bool visited[1286][128][60] = {false};
int directions[3][6] = {0, 0, 1, 0, 0, -1, 1, 0, 0, -1, 0, 0, 0, 1, 0, 0, -1, 0};
int count = 0;
int totalCount = 0;
bool valid(int i, int j, int k);
void dfs(int i, int j, int k);
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", &brain[i][j][k]);
}
}
}
for(int k = 0; k < L; k++){
for(int i = 0; i < M; i++){
for(int j = 0; j < N; j++){
if(!visited[i][j][k] && brain[i][j][k] == 1){
count = 0;
dfs(i, j, k);
if(count >= T){
totalCount += count;
}
}
}
}
}
printf("%d\n", totalCount);
return 0;
}
bool valid(int i, int j, int k){
if(i >= 0 && i < M && j >= 0 && j < N && k >= 0 && k < L){
return true;
}else{
return false;
}
}
void dfs(int i, int j, int k){
visited[i][j][k] = true;
count++;
for(int t = 0; t < 6; t++){
int newI = directions[0][t] + i;
int newJ = directions[1][t] + j;
int newK = directions[2][t] + k;
if(valid(newI, newJ, newK) && !visited[newI][newJ][newK] && brain[newI][newJ][newK] == 1){
dfs(newI, newJ, newK);
}
}
}
C++解题报告:
思路二:广度优先遍历
三维广度优先遍历,和二维情况一样,只不过多了几个方向。用结构体node来存储入队元素的3个坐标值。
C++代码:
#include<iostream>
#include<queue>
using namespace std;
struct node {
int i;
int j;
int k;
node(int _i, int _j, int _k) : i(_i), j(_j), k(_k) {};
};
int M, N, L, T;
int brain[1286][128][60];
bool inq[1286][128][60] = {false};
int directions[3][6] = {0, 0, 1, 0, 0, -1, 1, 0, 0, -1, 0, 0, 0, 1, 0, 0, -1, 0};
int count = 0;
int totalCount = 0;
bool valid(int i, int j, int k);
void bfs(int i, int j, int k);
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", &brain[i][j][k]);
}
}
}
for(int k = 0; k < L; k++) {
for(int i = 0; i < M; i++) {
for(int j = 0; j < N; j++) {
if(!inq[i][j][k] && brain[i][j][k] == 1) {
count = 0;
bfs(i, j, k);
if(count >= T) {
totalCount += count;
}
}
}
}
}
printf("%d\n", totalCount);
return 0;
}
bool valid(int i, int j, int k) {
if(i >= 0 && i < M && j >= 0 && j < N && k >= 0 && k < L) {
return true;
} else {
return false;
}
}
void bfs(int i, int j, int k) {
queue<node> q;
q.push(node(i, j, k));
inq[i][j][k] = true;
while(!q.empty()) {
node now = q.front();
q.pop();
count++;
for(int t = 0; t < 6; t++) {
int newI = directions[0][t] + now.i;
int newJ = directions[1][t] + now.j;
int newK = directions[2][t] + now.k;
if(valid(newI, newJ, newK) && !inq[newI][newJ][newK] && brain[newI][newJ][newK] == 1) {
q.push(node(newI, newJ, newK));
inq[newI][newJ][newK] = true;
}
}
}
}
C++解题报告: