在诊断肿瘤疾病时,计算肿瘤体积是很重要的一环。给定病灶扫描切片中标注出的疑似肿瘤区域,请你计算肿瘤的体积。

输入格式:

输入第一行给出4个正整数:M、N、L、T,其中M和N是每张切片的尺寸(即每张切片是一个M×N的像素矩阵。最大分辨率是1286×128);L(≤60)是切片的张数;T是一个整数阈值(若疑似肿瘤的连通体体积小于T,则该小块忽略不计)。

最后给出L张切片。每张用一个由0和1组成的M×N的矩阵表示,其中1表示疑似肿瘤的像素,0表示正常像素。由于切片厚度可以认为是一个常数,于是我们只要数连通体中1的个数就可以得到体积了。麻烦的是,可能存在多个肿瘤,这时我们只统计那些体积不小于T的。两个像素被认为是“连通的”,如果它们有一个共同的切面,如下图所示,所有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

代码长度限制

16 KB

时间限制

600 ms

内存限制

64 MB

栈限制

8192 KB

Java实现:

/**
 * 【题目核心思路】
 * 1. 问题转化:
 * - 题目给的是 L 张 M*N 的切片,其实就是一个 M*N*L 的三维空间。
 * - “连通体”体积 = 三维空间中 6-连通(上下、左右、前后)的“1”的个数。
 * - 目标:找出所有体积 >= T 的连通块,求它们的体积总和。
 * * 2. 算法选型:
 * - 选用 BFS 广搜:三维空间像素多达百万级,DFS 递归太深会导致栈溢出。
 */

import java.util.*;
import java.io.*;

public class Main {
    static int M, N, L, T;
    static byte[] matrix; // 扁平化存储:matrix[l * M * N + m * N + n]
    static int MN;        // 缓存切片面积,减少重复乘法

    public static void main(String[] args) throws Exception {
        Reader sc = new Reader();
        M = sc.nextInt();
        N = sc.nextInt();
        L = sc.nextInt();
        T = sc.nextInt();

        MN = M * N;
        int totalSize = L * MN;
        matrix = new byte[totalSize];

        // 字节流高速灌入数据
        for (int i = 0; i < totalSize; i++) {
            matrix[i] = (byte) sc.nextInt();
        }

        int totalVolume = 0;
        int[] queue = new int[totalSize]; // 整个程序共用一个静态队列,避免反复分配内存

        for (int i = 0; i < totalSize; i++) {
            // 发现疑似肿瘤起点
            if (matrix[i] == 1) {
                int volume = bfs(i, queue);
                if (volume >= T) totalVolume += volume;
            }
        }
        System.out.println(totalVolume);
    }

    /**
     * BFS 核心:像水流一样扩散搜寻连通的 1
     */
    private static int bfs(int start, int[] queue) {
        int head = 0, tail = 0;
        queue[tail++] = start; // 起点入队
        matrix[start] = 0;     // 标记已处理

        while (head < tail) {
            int curr = queue[head++];
            
            // 将一维索引还原为三维坐标,用于边界检查
            int curL = curr / MN;           
            int curM = (curr % MN) / N;     
            int curN = curr % N;            

            // 检查 6 个连通方向(上下前后左右)
            // 每次入队前直接改 matrix 状态,防止同一个点被重复入队
            
            // 1. L 轴上下
            if (curL + 1 < L) { check(curr + MN, queue, tail); if (found) tail++; }
            if (curL - 1 >= 0) { check(curr - MN, queue, tail); if (found) tail++; }
            // 2. M 轴前后
            if (curM + 1 < M) { check(curr + N, queue, tail); if (found) tail++; }
            if (curM - 1 >= 0) { check(curr - N, queue, tail); if (found) tail++; }
            // 3. N 轴左右
            if (curN + 1 < N) { check(curr + 1, queue, tail); if (found) tail++; }
            if (curN - 1 >= 0) { check(curr - 1, queue, tail); if (found) tail++; }
        }
        return tail; // tail 即为该连通块的总体积
    }

    static boolean found;
    /**
     * 辅助判定:合法则入队并标记
     */
    private static void check(int nIdx, int[] queue, int tail) {
        found = false;
        if (matrix[nIdx] == 1) {
            matrix[nIdx] = 0; 
            queue[tail] = nIdx;
            found = true;
        }
    }

    static class Reader {
        BufferedInputStream in = new BufferedInputStream(System.in);
        
        int nextInt() throws Exception {
            int res = 0;
            int b = in.read();
            while (b != -1 && (b < '0' || b > '9')) b = in.read();
            if (b == -1) return -1;
            while (b != -1 && b >= '0' && b <= '9') {
                res = res * 10 + (b - '0');
                b = in.read();
            }
            return res;
        }
    }
}

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐