题目
问题描述 俄罗斯方块是俄罗斯人阿列克谢·帕基特诺夫发明的一款休闲游戏。 游戏在一个15行10列的方格图上进行,方格图上的每一个格子可能已经放置了方块,或者没有放置方块。每一轮,都会有一个新的由4个小方块组成的板块从方格图的上方落下,玩家可以操作板块左右移动放到合适的位置,当板块中某一个方块的下边缘与方格图上的方块上边缘重合或者达到下边界时,板块不再移动,如果此时方格图的某一行全放满了方块,则该行被消除并得分。 在这个问题中,你需要写一个程序来模拟板块下落,你不需要处理玩家的操作,也不需要处理消行和得分。 具体的,给定一个初始的方格图,以及一个板块的形状和它下落的初始位置,你要给出最终的方格图。 输入格式 输入的前15行包含初始的方格图,每行包含10个数字,相邻的数字用空格分隔。如果一个数字是0,表示对应的方格中没有方块,如果数字是1,则表示初始的时候有方块。输入保证前4行中的数字都是0。 输入的第16至第19行包含新加入的板块的形状,每行包含4个数字,组成了板块图案,同样0表示没方块,1表示有方块。输入保证板块的图案中正好包含4个方块,且4个方块是连在一起的(准确的说,4个方块是四连通的,即给定的板块是俄罗斯方块的标准板块)。 第20行包含一个1到7之间的整数,表示板块图案最左边开始的时候是在方格图的哪一列中。注意,这里的板块图案指的是16至19行所输入的板块图案,如果板块图案的最左边一列全是0,则它的左边和实际所表示的板块的左边是不一致的(见样例) 输出格式 输出15行,每行10个数字,相邻的数字之间用一个空格分隔,表示板块下落后的方格图。注意,你不需要处理最终的消行。 样例输入 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 1 1 1 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 1 0 0 0 0 3 样例输出 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 1 1 1 1 1 1 1 0 0 0 0 1 1 0 0 0 0 |
---|
思路
我的想法是,找到板块与地图相碰(即停止)的行数以及在地图上的行数,然后再把板块拼上去。
用两个二维数组分别存地图和板块,我用了三重循环(服了)
遍历15行,每一行都与板块4x4对比,如果有两个地方都等于1,就说明在这里停止。
逻辑也改了好几次,从70-40-80分,改不动了。。
坑:
- break只能跳出最近循环,如果想跳出多重循环,要么用goto(不推荐但做题很好用。。)或者在各个循环地方加判断条件。
- 要考虑边界问题!
代码
我的80分代码
```cppinclude
using namespace std;
const int row =15; const int col =10;
int map[row][col]; int cube[4][4];
int main(){ int n;//从那列开始
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
cin>>map[i][j];
}
}
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
cin>>cube[i][j];
}
}
cin>>n;
int map_stop,cube_stop;//地图停止行和方块停止行
//停止状态 应该是有碰到就算停止。所以应该每次都遍历所有4x4方块
for(int i=0;i<row;i++){
//int flag =3;//方块最低层开始
for(int a=3;a>=0;a--){
for(int j=n-1;j<n+3;j++){
if(map[i][j]==1&&cube[a][j-n+1]==1){
//cout<<i+1<<" "<<j<<endl;
map_stop =i-1;
cube_stop =a;
//break语句只能跳出离它最近的一层循环
//break;//找到停止行
goto here;
}
}
}
}
here: //cout<<map_stop<<” “<<cube_stop;
//填充
for(int i=map_stop-cube_stop;i<map_stop-cube_stop+4;i++){
for(int j=n-1;j<n+3;j++){
if(i<row){
if(map[i][j]==0){
map[i][j] =cube[i-map_stop+cube_stop][j-n+1];
}
//cout<<map[i][j]<<" ";
}else{
goto end;
}
}
//cout<<endl;
}
end: for(int i=0;i<row;i++){ for(int j=0;j<col;j++){ cout<<map[i][j]<<” “; } cout<<endl; }
return 0;
}
<a name="LaLoC"></a>
## 我的修改后的100分代码
....参考了网友代码,我就是试着加了下边界条件,结果就满分了....<br />如果没有考虑边界,测试用例设计为:<br />0 0 0 0<br />0 0 0 0<br />0 0 0 0<br />1 1 1 1<br />按照原来的80分代码那就错误了,无法停止。
```cpp
#include<iostream>
using namespace std;
const int row =15;
const int col =10;
int map[row+1][col];
int cube[4][4];
int main(){
int n;//从那列开始
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
cin>>map[i][j];
}
}
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
cin>>cube[i][j];
}
}
// 底边全放1 避免边界问题
for(int j=0; j<col; j++)
map[row][j] = 1;
cin>>n;
int map_stop,cube_stop;//地图停止行和方块停止行
//停止状态 应该是有碰到就算停止。所以应该每次都遍历所有4x4方块
for(int i=0;i<row;i++){
//int flag =3;//方块最低层开始
for(int a=3;a>=0;a--){
for(int j=n-1;j<n+3;j++){
if(map[i+1][j]==1&&cube[a][j-n+1]==1){
//cout<<i+1<<" "<<j<<endl;
map_stop =i;
cube_stop =a;
//break语句只能跳出离它最近的一层循环
//break;//找到停止行
goto here;
}
}
}
}
here:
//cout<<map_stop<<" "<<cube_stop;
//填充
for(int i=map_stop-cube_stop;i<map_stop-cube_stop+4;i++){
for(int j=n-1;j<n+3;j++){
if(i<row){
if(map[i][j]==0){
map[i][j] =cube[i-map_stop+cube_stop][j-n+1];
}
//cout<<map[i][j]<<" ";
}else{
goto end;
}
}
//cout<<endl;
}
end:
for(int i=0;i<row;i++){
for(int j=0;j<col;j++){
cout<<map[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
网友的满分代码
/* CCF201604-2 俄罗斯方块 */
#include <iostream>
const int ROW = 15;
const int COL = 10;
const int N = 4;
int board[ROW+1][COL];
int block[N][N];
struct {
int row, col;
} coords[N];
using namespace std;
int main()
{
int row, col;
// 输入数据
for(int i=0; i<ROW; i++)
for(int j=0; j<COL; j++)
cin >> board[i][j];
for(int i=0; i<N; i++)
for(int j=0; j<N; j++)
cin >> block[i][j];
cin >> col;
// 底边全放1 避免边界问题
for(int j=0; j<COL; j++)
board[ROW][j] = 1;
// 提取小方块坐标
int k = 0;
for(int i=N-1; i>=0; i--)
for(int j=0; j<N; j++)
if(block[i][j] == 1) {
coords[k].row = i;
coords[k].col = j;
k++;
}
// 模拟小方块落下过程
row = 1;//已落下一行 是排除了完全无法落下的情况吗?
col--; //因为下标从0开始 所以这里输入的col要-1
bool checkflag;
for(;;) {
checkflag = false;
for(int i=0; i<N; i++)
if(board[row + coords[i].row][col + coords[i].col] == 1) {
checkflag = true;
break;
}
if(checkflag)
break;
row++;
}
row--;//找到相碰的行 所以要再往上一行(跟我的思路挺相似的啊?)
// 合并小方块到方格
for(int i=0; i<N; i++)
board[row + coords[i].row][col + coords[i].col] = 1;
// 输出结果
for(int i=0; i<ROW; i++) {
for(int j=0; j<COL; j++) {
if(j != 0)
cout << " ";
cout << board[i][j];
}
cout << endl;
}
return 0;
}