保留方块图案的四列定位,逐行试探下落到首次碰撞前的位置。
OJ: shumeng
题目 ID: CSP201604B
难度:入门
标签:模拟二维数组
日期: 2026-07-31 16:21
形式化题目
给定一个
思路
板块只做竖直下落,形状和列位置全程不变,因此只需确定落定的行号。
定位板块
输入给出的列号是“图案最左边一列”所在的列,即使这一列全为 0 也不能裁去图案。把图案的左上角对齐该列,用一个变量 top 记录图案当前所在的行。
试探下落
每次尝试把 top 加 1,检查图案中所有值为 1 的格子:
- 下移后行号超过棋盘底部;
- 或者与棋盘上已有的方块重叠。
只要出现任何一种情况,板块就不能再下落,top 保持为当前值。否则更新 top 并继续。
下图示意板块从 top 行尝试下移一行的检查(X 为板块实心格):
text
下移前 top 行 试探下移一行
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . X X X . <- 新位置,目标格必须为空且不越界
. . . X X X . . . . . . X .
. . . . . X . . . . . . . .右侧新位置的每个 X 都要落在空且不越界的格子里,才能把 top 更新为 top + 1。
写入棋盘
落定后,把板块中所有值为 1 的格子写入棋盘,最后按行输出整个棋盘。
代码
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-31 16:21
* update_at: 2026-08-17 22:48
*/
#include <bits/stdc++.h>
using namespace std;
const int ROWS = 15;
const int COLS = 10;
int board[ROWS][COLS]; // 方格图,1 表示该格已有方块
int block[4][4]; // 下落板块图案,1 表示该格有方块
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
cin >> board[i][j];
}
}
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
cin >> block[i][j];
}
}
int start_column;
cin >> start_column;
start_column--; // 输入列号从 1 开始,转为 0 基下标
// 从第 0 行开始,每次试探下移一行:板块所有实心格都要仍能放下。
int top = 0;
while (true) {
bool can_fall = true;
for (int i = 0; i < 4 && can_fall; i++) {
for (int j = 0; j < 4; j++) {
if (block[i][j] == 0) {
continue;
}
int row = top + 1 + i;
int column = start_column + j;
// 下移一行后越界,或与已有方块重叠,都不能再下落
if (row >= ROWS || board[row][column]) {
can_fall = false;
break;
}
}
}
if (!can_fall) {
break;
}
top++;
}
// 把板块写入最终落定位置
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (block[i][j]) {
board[top + i][start_column + j] = 1;
}
}
}
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
if (j > 0) {
cout << ' ';
}
cout << board[i][j];
}
cout << '\n';
}
return 0;
}复杂度
- 时间:每次下落试探扫描 16 个格子,最多下落到第 15 行,时间复杂度为
,可视为常数。 - 空间:棋盘与板块数组大小固定,空间复杂度为
。
总结
下落判断只检查板块中值为 1 的格子,值为 0 的格子不影响碰撞。起始列对应图案最左一列,即使图案左侧为全 0 也要保留该列定位。题目不要求消行,落定后直接输出即可。