ccf题库中2016年4月2日俄罗斯方块问题

时间:2023-03-09 00:28:37
ccf题库中2016年4月2日俄罗斯方块问题

题目如下:

问题描述
  俄罗斯方块是俄罗斯人阿列克谢·帕基特诺夫发明的一款休闲游戏。
  游戏在一个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个数字,相邻的数字之间用一个空格分隔,表示板块下落后的方格图。注意,你不需要处理最终的消行。
样例输入 样例输出

网上一般是模拟方块下落的过程,这种方法简洁,易于理解,代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
using namespace std;
struct Node{
int x;
int y;
};
int main()
{
int s[][];
Node t[];
for(int i=;i<;i++)
{
for(int j=;j<;j++)
{
cin>>s[i][j];
}
}
int count=;
for(int i=;i<;i++)
{
for(int j=;j<;j++)
{
int temp;
cin>>temp;
if(temp==)
{
t[count].x=i;
t[count].y=j;
count++;
}
}
}
int col;
cin>>col;
if(col+>=)
{
return ;
}else{
for(int i=;i<;i++)
{
t[i].y+=col-;
}
}
int flag=;
while()
{
for(int i=;i<;i++)
{
if(s[t[i].x][t[i].y])
{
flag=;
break;
}
}
if(flag)
{
break;
}else{
for(int i=;i<;i++)
{
t[i].x++;
}
}
}
if(flag==)
{
for(int i=;i<;i++)
{
s[t[i].x-][t[i].y]=;
}
}
for(int i=;i<;i++)
{
for(int j=;j<;j++)
{
cout<<s[i][j]<<" ";
}
cout<<endl;
}
return ;
}

我刚开始的想法是,为什么不从最后一行开始,那样不是更快吗?后来我发现这个想法不对,从下往上找,要一直遍历到第0行,这样的计算量特别大。

下面,我说说自己的想法:先通过遍历找到对应方块在大矩阵中的最下面一行,然后以这个行数为标准来将图形填充到大的矩阵中。详细说明,在代码中。

#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;
struct Node{
int x;
int y;
int row;
};
int cmp(Node x,Node y)
{
return x.x>y.x;
}
int main()
{
int s[][];
Node t[];
Node temp[];//在这里t用作遍历时的数组,temp主要是方便赋值
for(int i=;i<;i++)
{
for(int j=;j<;j++)
{
cin>>s[i][j];
}
}
int count=;
for(int i=;i<;i++)
{
for(int j=;j<;j++)
{
int tem;
cin>>tem;
if(tem==)
{
t[count].x=i;
t[count].y=j;
t[count].row=;
temp[count].x=i;
temp[count].y=j;
temp[count].row=;
count++;
}
}
}
int col;
cin>>col;
if(col+>=)
{
return ;
}else{
for(int i=;i<;i++)
{
t[i].y+=col-;
temp[i].y+=col-;
}
}
sort(t,t+,cmp);
sort(temp,temp+,cmp);
//-----------------找出最下面的一行-------------------------
int row,real_row;
for(real_row=;real_row>=;real_row--){//一行一行的遍历,从最底层开始。
row=real_row;
int flag;
for(;row>=;row--)//将从最低行一直遍历到第0行
{
int temp_row=row;
flag=;
for(int j=;j<;j++)
{
if(j==){
if(temp_row<){
break;
}
if(s[temp_row][t[j].y]==){
flag=;//标记失败
break;
}else{
temp_row=temp_row-t[j].x+t[j+].x;
}
}else{
if(temp_row<){
break;
}
if(s[temp_row][t[j].y]==){
flag=;//标记失败
break;
}else{
if(j<=){
temp_row=temp_row-t[j].x+t[j+].x;
}
}
}
}
if(flag==){//出现失败后没有必要在遍历了,跳出循环,对下一个real_row进行从real_row到0的遍历
break;
}
}
if(flag==){//说明出现了满足情况的行数,停止执行。
break;
}
}
//--------------重新赋值--------------------
// cout<<"最终行数为:"<<real_row<<endl;
for(int i=;i<;i++)
{
if(i==){
temp[i].x=real_row;
real_row=real_row-t[].x+t[].x;
}else{
temp[i].x=real_row;
if(i<=){
real_row=real_row-t[i].x+t[i+].x;//利用小矩阵中函数差,来确定对应的大矩阵中的行数,例如,t[0]在小矩阵中是第二行,t[1]在小矩阵中是第一行,t[0]在大矩阵中是第13行,那么t[1]应该是13-2+1=12行
}
}
s[temp[i].x][temp[i].y]=;
}
//--------------输出结果--------------------
for(int i=;i<;i++)
{
for(int j=;j<;j++)
{
cout<<s[i][j]<<" ";
}
cout<<endl;
}
return ;
}