首页 > 试题广场 >

小红的矩阵染色

[编程题]小红的矩阵染色
  • 热度指数:5594 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
小红拿到了一个矩阵,初始有一些格子被染成了黑色。现在小红希望把最多k个未被染成黑色的格子染成红色,具体的计分方式是:如果一个红色格子下方相邻的格子也是红色,那么这个红色格子可以获得1分。
小红想知道,最多可以得到多少分?

输入描述:
第一行输入三个正整数n,m,k,代表矩阵的行数和列数、以及小红最多可以染色的格子数量。
接下来的n行,每行输入一个长度为m的字符串,用来表示矩阵的初始染色情况。'*'字符代表黑色,'o'字符代表白色。
1\leq n,m \leq 1000
1\leq k \leq n*m


输出描述:
一个整数,代表小红可以获得的最大分数。
示例1

输入

4 4 3
*o*o
oooo
****
oooo

输出

1

说明

将矩阵染色成如下样式即可('r'代表红色):
*r*o
oroo
****
oooo

示例2

输入

3 3 3
*o*
*o*
*o*

输出

2
import java.util.Scanner;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();  // 矩阵行数
        int m = sc.nextInt();  // 矩阵列数
        int k = sc.nextInt();  // 最多可染色的格子数
        char[][] matrix = new char[n][m];
        
        // 读取矩阵数据
        for (int i = 0; i < n; i++) {
            matrix[i] = sc.next().toCharArray();
        }

        List<Integer> blockLengths = new ArrayList<>();
        
        // 按列遍历,找出所有垂直连续的白色块(长度≥2)
        for (int j = 0; j < m; j++) {  // 遍历每一列
            int currentBlockLength = 0;  // 当前连续白色块的长度
            for (int i = 0; i < n; i++) {  // 遍历列中的每一行
                if (matrix[i][j] == 'o') {  // 遇到白色格子,增加块长度
                    currentBlockLength++;
                } else {  // 遇到非白色格子(黑色)
                    // 若当前块长度≥2,记录下来(只有≥2的块才能产生得分)
                    if (currentBlockLength >= 2) {
                        blockLengths.add(currentBlockLength);
                    }
                    currentBlockLength = 0;  // 重置块长度
                }
            }
            // 处理列末尾可能存在的连续白色块
            if (currentBlockLength >= 2) {
                blockLengths.add(currentBlockLength);
            }
        }

        // 按块长度从大到小排序(优先处理长块,能产生更多得分)
        Collections.sort(blockLengths, Collections.reverseOrder());

        int score = 0;
        // 遍历所有块,计算最大得分
        for (int length : blockLengths) {
            if (k == 0) break;  // 染色次数用尽,退出
            
            // 取当前块长度与剩余染色次数的较小值(最多染这么多格子)
            int cellsToDye = Math.min(k, length);
            
            // 只有染色数≥2时才能产生得分(连续2个格子产生1分,3个产生2分,以此类推)
            if (cellsToDye >= 2) {
                score += cellsToDye - 1;
            }
            
            k -= cellsToDye;  // 消耗染色次数
        }

        System.out.println(score);
    }
}

发表于 2025-08-31 11:26:10 回复(0)