2012年华为杯校园编程大赛决赛
类别:软件C/C++语言
编程题(共1题,100分。请上机编写程序,按题目要求提交文件。测试用例不对考生公开,凡不满足提交要求导致不能运行或用例不通过,不予评分。)
1. 俄罗斯方块之棋盘覆盖
俄罗斯方块是一款风靡全球的益智类游戏。由俄罗斯人阿列克谢·帕基特诺夫发明,故得此名。俄罗斯方块的基本规则是移动、旋转和摆放游戏自动输出的各种方块,使之排列成完整的一行或多行并且消除得分。由于上手简单、老少皆宜,从而家喻户晓,风靡世界。
本试题是在俄罗斯方块几种常见的方块基础上,在指定大小和障碍的棋盘上,用标准的方块形状,完成对棋盘的覆盖。用于覆盖棋盘的方块可以是下文所给出方块的全集,也可以是其中的任意一个子集,且使用的方块数量不限,形状变化不限。
l 棋盘大小:
棋盘大小为21行21列的正方形。按照从上到下,从左到右,从1开始,依次进行编号,直到最右下方的格子标识为441。
l 可选方块:
可选方块为标准的俄罗斯方块形状,包括其标准的旋转变化。基本形状如图所示:
各形状的变化如图所示(字母为方块编号):
a b
c d
e f
g
l 障碍说明:
棋盘上仅有一处障碍无法放置方块,障碍可处于棋盘任意位置。障碍为基本形状a及其所有的旋转变化,如图所示:
l 输入输出要求:
输入文件名为testin.txt,格式如下所示,各数字用空格隔开,各数字表示棋盘格子编号。
2 3 22 23
该输入表示障碍位于棋盘的左上角。
输出文件名为testout.txt,要求先输出棋盘覆盖结果,再输出未覆盖的格子个数。输出棋盘用21行21列数字/字母表示,其中0表示未覆盖的格子,1表示障碍,字母表示对应方块编号(字母对应关系见“可选方块”一节)。最后输出未覆盖格子个数。这里以6行10列棋盘举例示意输出格式(注意:实际输出应该是21行21列,对应方块形状用对应的字母表示):
0 e 0 0 0 0 f f f f
e e 0 0 0 1 1 g g g
e 0 0 0 1 1 0 0 0 g
a 0 0 0 c 0 d d 0 0
a a 0 0 c 0 d d b 0
0 a 0 0 c c 0 b b b
28
l 要求:
1、 用所提供的方块尽可能覆盖棋盘并输出结果;
2、 在(1)的基础上,棋盘上的空格越少越好。
l 交付件要求
C/C++:需要提交可执行文件和压缩打包的源代码工程
JAVA:需要提交压缩打包的整个编码工程目录
#include <fstream>
#include <iostream>
using namespace std;
/*******************************************************************************
* The maximum map width, height and block size
*******************************************************************************/
const int M_W = 21;
const int M_H = 21;
const int M_N = 4;
/*******************************************************************************
* Current map width, height
*******************************************************************************/
int M_CW = M_W;
int M_CH = M_H;
/*******************************************************************************
* Map for game
*******************************************************************************/
const int M_S = M_W > M_H ? M_W : M_H;
char map[M_S][M_S] = {0};
/*******************************************************************************
* Base class
*******************************************************************************/
class Base
{
public:
Base(){}
virtual ~Base(){}
virtual char GetIDC(void) = 0;
virtual bool FillAt(int x, int y) = 0;
virtual bool RemoveAt(int x, int y) = 0;
};
/*******************************************************************************
* Block
*******************************************************************************/
template<char idc>
class Block : public Base
{
public:
/***************************************************************************
* Initialize
***************************************************************************/
Block()
{
for (int i = 0; i < M_N; i++)
{
pos[i] = -1;
}
}
virtual ~Block(){}
/***************************************************************************
* Get IDC
***************************************************************************/
virtual char GetIDC(void)
{
return idc;
}
/***************************************************************************
* Fill at (x, y)
***************************************************************************/
virtual bool FillAt(int x, int y)
{
bool bret;
for (int i = 0; i < 4; i++)
{
bret = CheckMap(x, y);
if (bret)
{
SetMap(x, y);
return true;
}
RotateRight();
}
return false;
}
/***************************************************************************
* Remove at (x, y)
***************************************************************************/
virtual bool RemoveAt(int x, int y)
{
for (int i = 0; i < M_N; i++)
{
if (pos[i] >= 0)
{
map[pos[i]/M_W][pos[i]%M_W] = '0';
pos[i] = -1;
}
}
return true;
}
/***************************************************************************
* Check at (x, y)
***************************************************************************/
virtual bool CheckMap(int x, int y)
{
int i, j;
int xbs, ybs;
int count = 0;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
if (block[i][j] == 1)
{
if (count == 0)
{
xbs = i;
ybs = j;
}
count++;
int nx = x+i-xbs;
int ny = y+j-ybs;
if (nx < 0 || nx >= M_H || ny < 0 || ny >= M_W ||
map[nx][ny] != '0')
{
return false;
}
}
}
}
return true;
}
/***************************************************************************
* Set at (x, y)
***************************************************************************/
virtual bool SetMap(int x, int y)
{
int i, j;
int xbs, ybs;
int count = 0;
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
if (block[i][j] == 1)
{
if (count == 0)
{
xbs = i;
ybs = j;
}
if (map[x+i-xbs][y+j-ybs] != '0')
{
return false;
}
pos[count++] = (x+i-xbs) * 21 + (y+j-ybs) + 1;
map[x+i-xbs][y+j-ybs] = idc;
}
}
}
return true;
}
/***************************************************************************
* Show block
***************************************************************************/
static void Show(void)
{
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
cout << (block[i][j] == 1 ? '*' : ' ') << " ";
}
cout << endl;
}
}
protected:
/***************************************************************************
* Rotate Left
***************************************************************************/
static void RotateLeft(void)
{
int i, j;
char tmp_block[4][4];
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
tmp_block[i][j] = block[j][3-i];
}
}
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
block[i][j] = tmp_block[i][j];
}
}
}
/***************************************************************************
* Rotate right
***************************************************************************/
static void RotateRight(void)
{
int i, j;
char tmp_block[4][4];
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
tmp_block[i][j] = block[3-j][i];
}
}
for (i = 0; i < 4; i++)
{
for (j = 0; j < 4; j++)
{
block[i][j] = tmp_block[i][j];
}
}
}
protected:
/***************************************************************************
* Position data
***************************************************************************/
int pos[M_N];
/***************************************************************************
* Graph for block
***************************************************************************/
static char block[4][4];
};
/*******************************************************************************
* Graph for block
*******************************************************************************/
char Block<'a'>::block[4][4] = {
1, 0, 0, 0,
1, 1, 0, 0,
0, 1, 0, 0,
0, 0, 0, 0,
};
/*******************************************************************************
* Graph for block
*******************************************************************************/
char Block<'b'>::block[4][4] = {
1, 1, 1, 0,
0, 1, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
};
/*******************************************************************************
* Graph for block
*******************************************************************************/
char Block<'c'>::block[4][4] = {
1, 1, 1, 0,
1, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
};
/*******************************************************************************
* Graph for block
*******************************************************************************/
char Block<'d'>::block[4][4] = {
1, 1, 0, 0,
1, 1, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
};
/*******************************************************************************
* Graph for block
*******************************************************************************/
char Block<'e'>::block[4][4] = {
0, 1, 0, 0,
1, 1, 0, 0,
1, 0, 0, 0,
0, 0, 0, 0,
};
/*******************************************************************************
* Graph for block
*******************************************************************************/
char Block<'f'>::block[4][4] = {
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
1, 0, 0, 0,
};
/*******************************************************************************
* Graph for block
*******************************************************************************/
char Block<'g'>::block[4][4] = {
0, 1, 0, 0,
0, 1, 0, 0,
1, 1, 0, 0,
0, 0, 0, 0,
};
/*******************************************************************************
* Using global variable map as parameter
*******************************************************************************/
int solve(void)
{
int i, j;
int count = 0;
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
if (map[i][j] == '0')
{
Block<'a'> a;
Block<'b'> b;
Block<'c'> c;
Block<'d'> d;
Block<'e'> e;
Block<'f'> f;
Block<'g'> g;
bool bret = false;
bret = bret || d.FillAt(i, j);
bret = bret || f.FillAt(i, j);
bret = bret || c.FillAt(i, j);
bret = bret || g.FillAt(i, j);
bret = bret || a.FillAt(i, j);
bret = bret || e.FillAt(i, j);
bret = bret || b.FillAt(i, j);
if (bret)
{
count += 4;
}
}
}
}
return count;
}
/*******************************************************************************
* Map rotate
*******************************************************************************/
void map_rotate()
{
int i, j;
char tmp_map[M_S][M_S];
for (i = 0; i < M_S; i++)
{
for (j = 0; j < M_S; j++)
{
tmp_map[i][j] = map[j][M_S-1-i];
}
}
for (i = 0; i < M_S; i++)
{
for (j = 0; j < M_S; j++)
{
map[i][j] = tmp_map[i][j];
}
}
M_CH ^= M_CW ^= M_CH;
M_CW ^= M_CH;
}
/*******************************************************************************
* Check map and solve
*******************************************************************************/
int rotate_map_and_solve(void)
{
/***************************************************************************
* Save map
***************************************************************************/
int i, j;
char orig_map[M_H][M_W];
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
orig_map[i][j] = map[i][j];
}
}
/***************************************************************************
* Solve map
***************************************************************************/
char solve_map[M_H][M_W];
int solve_count = solve();
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
solve_map[i][j] = map[i][j];
}
}
/***************************************************************************
* Rotate and solve map
***************************************************************************/
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
map[i][j] = orig_map[i][j];
}
}
map_rotate();
char save_map[M_H][M_W];
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
save_map[i][j] = map[i][j];
}
}
int solve_count_rotate = solve();
if (solve_count_rotate > solve_count)
{
solve_count = solve_count_rotate;
map_rotate();
map_rotate();
map_rotate();
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
solve_map[i][j] = map[i][j];
}
}
}
/***************************************************************************
* Rotate and solve map
***************************************************************************/
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
map[i][j] = save_map[i][j];
}
}
map_rotate();
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
save_map[i][j] = map[i][j];
}
}
solve_count_rotate = solve();
if (solve_count_rotate > solve_count)
{
solve_count = solve_count_rotate;
map_rotate();
map_rotate();
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
solve_map[i][j] = map[i][j];
}
}
}
/***************************************************************************
* Rotate and solve map
***************************************************************************/
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
map[i][j] = save_map[i][j];
}
}
map_rotate();
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
save_map[i][j] = map[i][j];
}
}
solve_count_rotate = solve();
if (solve_count_rotate > solve_count)
{
solve_count = solve_count_rotate;
map_rotate();
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
solve_map[i][j] = map[i][j];
}
}
}
/***************************************************************************
* Set solve map
***************************************************************************/
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
map[i][j] = solve_map[i][j];
}
}
return solve_count;
}
/*******************************************************************************
* Check map and solve
*******************************************************************************/
int check_map_and_solve(void)
{
/***************************************************************************
* Save map
***************************************************************************/
int i, j;
char orig_map[M_H][M_W];
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
orig_map[i][j] = map[i][j];
}
}
/***************************************************************************
* Solve map
***************************************************************************/
char solve_map[M_H][M_W];
int solve_count = solve();
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
solve_map[i][j] = map[i][j];
}
}
/***************************************************************************
* Rotate and solve map
***************************************************************************/
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
map[i][j] = orig_map[i][j];
}
}
int solve_count_rotate = rotate_map_and_solve();
if (solve_count_rotate > solve_count)
{
solve_count = solve_count_rotate;
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
solve_map[i][j] = map[i][j];
}
}
}
/***************************************************************************
* Rotate and solve map
***************************************************************************/
int xf = -1;
int yf = -1;
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
map[i][j] = orig_map[i][j];
if (map[i][j] == '1' && xf < 0)
{
xf = i;
yf = j;
}
}
}
/***************************************************************************
* Find '1' and check if we can add some block
***************************************************************************/
if (xf >= 0)
{
/***********************************************************************
* Check :
* 1 1 1
* 1 1 or 1 1
* 1
***********************************************************************/
int solve_count_match = 0;
if (map[xf][yf+1] == '1')
{
/*******************************************************************
* Add c c c
* c
*******************************************************************/
if (xf >= 1)
{
map[xf-1][yf-1] = 'c';
map[xf-1][yf] = 'c';
map[xf-1][yf+1] = 'c';
map[xf][yf-1] = 'c';
solve_count_match += 4;
}
/*******************************************************************
* Add c
* c c c
*******************************************************************/
if (xf < M_H - 2)
{
map[xf+1][yf+1] = 'c';
map[xf+2][yf-1] = 'c';
map[xf+2][yf] = 'c';
map[xf+2][yf+1] = 'c';
solve_count_match += 4;
}
solve_count_match += rotate_map_and_solve();
if (solve_count_match > solve_count)
{
solve_count = solve_count_match;
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
solve_map[i][j] = map[i][j];
}
}
}
}
else
{
/*******************************************************************
* Add c
* c
* c c
*******************************************************************/
if (yf > 0)
{
map[xf][yf-1] = 'c';
map[xf+1][yf-1] = 'c';
map[xf+2][yf-1] = 'c';
map[xf+2][yf] = 'c';
solve_count_match += 4;
}
/*******************************************************************
* Add c c
* c
* c
*******************************************************************/
if (yf < M_W - 2)
{
map[xf][yf+1] = 'c';
map[xf][yf+2] = 'c';
map[xf+1][yf+2] = 'c';
map[xf+2][yf+2] = 'c';
solve_count_match += 4;
}
solve_count_match += rotate_map_and_solve();
if (solve_count_match > solve_count)
{
solve_count = solve_count_match;
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
solve_map[i][j] = map[i][j];
}
}
}
}
}
/***************************************************************************
* Set solve map
***************************************************************************/
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
map[i][j] = solve_map[i][j];
}
}
return solve_count;
}
/*******************************************************************************
* Test function
*******************************************************************************/
void test()
{
/***************************************************************************
* Clear map
***************************************************************************/
int i, j;
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
map[i][j] = '0';
}
}
/***************************************************************************
* Test map
***************************************************************************/
int a, b;
for (a = 0; a < M_H; a++)
{
for (b = 0; b < M_W; b++)
{
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
map[i][j] = '0';
}
}
if (a < M_H - 2 && b < M_W - 1)
{
map[a][b] = '1';
map[a+1][b] = '1';
map[a+1][b+1] = '1';
map[a+2][b+1] = '1';
int m = check_map_and_solve();
if (m < 436)
{
cout << "At " << m <<": (" << a << "," << b <<")" << endl;
}
}
map[i][j] = '0';
}
}
/***************************************************************************
* Test map
***************************************************************************/
for (a = 0; a < M_H; a++)
{
for (b = 0; b < M_W; b++)
{
for (i = 0; i < M_H; i++)
{
for (j = 0; j < M_W; j++)
{
map[i][j] = '0';
}
}
if (a > 0 && a < M_H - 1 && b < M_W - 1)
{
map[a][b] = '1';
map[a][b+1] = '1';
map[a+1][b] = '1';
map[a+1][b-1] = '1';
int m = check_map_and_solve();
if (m < 436)
{
cout << "At " << m <<": (" << a << "," << b <<")" << endl;
}
}
map[i][j] = '0';
}
}
}
int main()
{
/***************************************************************************
* Test function
***************************************************************************/
test();
return 0;
/***************************************************************************
* Clear map
***************************************************************************/
for (int i = 0; i < M_H; i++)
{
for (int j = 0; j < M_W; j++)
{
map[i][j] = '0';
}
}
/***************************************************************************
* Read data from input file
***************************************************************************/
int n = 0;
ifstream ifs;
ifs.open("testin.txt");
if (ifs.is_open())
{
while (!ifs.eof())
{
int pos = -1;
ifs >> pos;
if (pos > 0)
{
n++;
pos--;
map[pos/M_W][pos%M_W] = '1';
}
}
ifs.close();
}
/***************************************************************************
* Solve this problem
***************************************************************************/
int m = check_map_and_solve();
/***************************************************************************
* Write data to output file
***************************************************************************/
ofstream ofs;
ofs.open("testout.txt");
if (ofs.is_open())
{
for (int i = 0; i < M_H; i++)
{
for (int j = 0; j < M_W; j++)
{
ofs << map[i][j] << " ";
}
ofs << endl;
}
ofs << M_H * M_W - n - m << endl;
ofs.close();
}
return 0;
}