First Step (ファーストステップ)

GitHub跳转原题关系图返回列表

枚举每个横向和纵向长度为 K 的连续区间,判断其中是否全部为空地;K=1 时单独计数空格。

OJ: luogu

题目 ID: P3654

难度:入门

标签:枚举矩阵python

日期: 2026-07-15 21:40

题意

给定一个 R x C 的矩阵,. 表示空地,# 表示障碍。要找出有多少种方法放下一条长度为 K 的直线队伍,方向可以横向或纵向,所有位置都必须是空地。

思路

直接枚举每个可能的起点。

横向放置时,起点 (row, col) 需要满足 col + K - 1 < C,然后检查这一段是否全是 .

纵向放置时,起点 (row, col) 需要满足 row + K - 1 < R,然后检查这一段是否全是 .

需要特别注意 K = 1。此时横向和纵向的同一个空格表示同一种站位,不能重复计数,所以直接统计空地数量。

Python 知识

  • all(...) 可以判断一段格子是否全部满足条件,并且遇到第一个不满足的格子会短路。
  • row.count(".") 可以统计一行中的空地数量。
  • range(c - k + 1) 控制横向起点,避免越界。

参考笔记:

  • /home/rainboy/mycode/hugo-blog/content/program_language/python/generator_expression.md
  • /home/rainboy/mycode/hugo-blog/content/program_language/python/input_output_and_strings.md

代码

python
r, c, k = map(int, input().split())
grid = [input().strip() for _ in range(r)]

if k == 1:
    print(sum(row.count(".") for row in grid))
else:
    answer = 0

    for row in range(r):
        for col in range(c - k + 1):
            if all(grid[row][col + offset] == "." for offset in range(k)):
                answer += 1

    for row in range(r - k + 1):
        for col in range(c):
            if all(grid[row + offset][col] == "." for offset in range(k)):
                answer += 1

    print(answer)
cpp
/**
 * Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
 * rbook: -> https://rbook.roj.ac.cn  https://rbook2.roj.ac.cn
 * rainboy的学习导航网站: https://idx.roj.ac.cn
 * create_at: 2026-07-27 00:00
 * update_at: 2026-07-27 00:00
 */
#include <bits/stdc++.h>
using namespace std;

int r, c, k;
char grid[105][105];

int main() {
    cin >> r >> c >> k;
    for (int i = 0; i < r; i++) cin >> grid[i];
    if (k == 1) {
        int ans = 0;
        for (int i = 0; i < r; i++)
            for (int j = 0; j < c; j++)
                if (grid[i][j] == '.') ans++;
        cout << ans << endl;
        return 0;
    }
    int ans = 0;
    for (int i = 0; i < r; i++) {
        for (int j = 0; j <= c - k; j++) {
            bool ok = true;
            for (int t = 0; t < k; t++)
                if (grid[i][j + t] != '.') { ok = false; break; }
            if (ok) ans++;
        }
    }
    for (int i = 0; i <= r - k; i++) {
        for (int j = 0; j < c; j++) {
            bool ok = true;
            for (int t = 0; t < k; t++)
                if (grid[i + t][j] != '.') { ok = false; break; }
            if (ok) ans++;
        }
    }
    cout << ans << endl;
    return 0;
}

复杂度

每个起点最多检查 K 个格子,时间复杂度为 O(RCK)O(RCK),空间复杂度为 O(RC)O(RC)

总结

矩阵枚举题先确定“起点范围”,再写合法性检查。K=1 的重复计数是本题最容易漏掉的边界。