首页 > 试题广场 >

小红的矩阵染色

[编程题]小红的矩阵染色
  • 热度指数:3736 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
\hspace{15pt}给定一个 n\times m 的矩阵,初始时部分格子已被染成黑色(用 ``\texttt{*}`` 表示),其余格子为空白(用 ``\texttt{o}`` 表示)。

\hspace{15pt}小红最多可以任选至多 k空白格子,将其染成红色。计分规则如下:
\hspace{23pt}\bullet\, 若某个红色格子的正下方(同一列下一行)也是红色,则该格子贡献 1 分;
\hspace{23pt}\bullet\, 其他情况不计分。

\hspace{15pt}请你帮小红计算,经过最优染色后,最多能获得多少分数。

输入描述:
\hspace{15pt}第一行输入三个整数 n,m,k\left(1\leqq n,m\leqq 10^3;\ 1\leqq k\leqq n\times m\right),分别表示矩阵行数、列数及最多可染红的格子数量。
\hspace{15pt}此后 n 行,每行输入一个长度为 m 的字符串 s_i,描述第 i 行初始状态:
\hspace{23pt}\bullet\, ``\texttt{*}`` 代表黑色格子,不能重新染色;
\hspace{23pt}\bullet\, ``\texttt{o}`` 代表空白格子,可选择染为红色。


输出描述:
\hspace{15pt}输出一个整数,表示小红通过最佳策略能够获得的最大分数。
示例1

输入

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

输出

1

说明

一种可行方案如下(``\texttt{r}`` 为染成红色后的格子):

\hspace{15pt}*r*o
\hspace{15pt}oroo
\hspace{15pt}****
\hspace{15pt}oooo

红色格子共有 2 个,其中正下方同列的红色对数为 1,因此得分 1
示例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-09-04 08:53:00 回复(0)
n, m, k = map(int, input().split())
array = [[x for x in input()] for _ in range(n)]
arr = [] # 记录每个连续空白可得分数 for col in range(m):
    coun = -1  for row in range(n): # 遇到黑色格子,存储分数,并重置  if array[row][col] == '*': if coun >= 0: # 避免连续黑色格子添加-1的情况  arr.append(coun)
            coun = -1  else:
            coun += 1  # 列尾时添加该分数到arr  if coun >= 0:
        arr.append(coun)
arr.sort(reverse=True)
score = 0 for i in range(len(arr)): if arr[i]+1 < k:
        score += arr[i]
        k -= (arr[i]+1) else:
        score += (k-1)
        k = 0  break print(score)
发表于 2025-10-04 18:36:18 回复(0)
#include <iostream>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n, m, k, score = 0;
    cin >> n >> m >> k;
    vector<string> vec(n);
    for (int i = 0; i < n; i++)
        cin >> vec[i];
    vector<int> white;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (white.empty())
                white.push_back(0);
            if (vec[j][i] == '*') {
                if (white.back() < 2)
                    white.pop_back();
                white.push_back(0);
                continue;
            }
            white.back()++;
        }
        if (!white.empty()&&white.back() < 2)
            white.pop_back();
        white.push_back(0);
    }
    white.pop_back();
    sort(white.begin(), white.end(), [](auto const & a, auto const & b) {
        return a > b;
    });
    for (int num : white) {
        if (num >= k){
            score += k - 1;
            break;
            }
        else {
            k -= num;
            score += num - 1;
        }
    }
    cout << score;
}

发表于 2025-09-20 12:10:08 回复(0)
n, m, k = map(int, input().split())
s = [list(input()) for _ in range(n)]
whitecol = []

for j in range(m):
    numwhite = 0
    for i in range(n):
        if s[i][j] == 'o':
            numwhite += 1
        else:
            if numwhite > 1:
                whitecol.append(numwhite)
            numwhite = 0
    # 处理列末尾的连续空白
    if numwhite > 1:
        whitecol.append(numwhite)

whitecol.sort(reverse=True)
score = 0
leftred = k

for x in whitecol:
    if leftred >= x:
        score += x - 1  # 连续x个空白染红可以得到x-1分
        leftred -= x
    elif leftred > 1:  # 如果剩余可染红格子数大于1,仍然可以得分
        score += leftred - 1
        leftred = 0
        break

print(score)

发表于 2025-08-25 15:16:53 回复(0)