在http://blog.thpiano.com/?p=579看到有人贴出第四届华为编程大赛决赛试题答案,研究了一下,发现有错误,下面将修改正确的代码贴出。
题目是这样的:
=======================================================================
编程题(共1题,100分。请上机编写程序,按题目要求提交文件。测试用例不对考生公开,凡不满足提交要求导致不能运行或用例不通过,不予评分。)
1. 俄罗斯方块之棋盘覆盖
俄罗斯方块是一款风靡全球的益智类游戏。由俄罗斯人阿列克谢·帕基特诺夫发明,故得此名。俄罗斯方块的基本规则是移动、旋转和摆放游戏自动输出的各种方块,使之排列成完整的一行或多行并且消除得分。由于上手简单、老少皆宜,从而家喻户晓,风靡世界。
本试题是在俄罗斯方块几种常见的方块基础上,在指定大小和障碍的棋盘上,用标准的方块形状,完成对棋盘的覆盖。用于覆盖棋盘的方块可以是下文所给出方块的全集,也可以是其中的任意一个子集,且使用的方块数量不限,形状变化不限。
棋盘大小:
棋盘大小为21行21列的正方形。按照从上到下,从左到右,从1开始,依次进行编号,直到最右下方的格子标识为441。
可选方块:
可选方块为标准的俄罗斯方块形状,包括其标准的旋转变化。基本形状如图所示:
各形状的变化如图所示(字母为方块编号):
障碍说明:
棋盘上仅有一处障碍无法放置方块,障碍可处于棋盘任意位置。障碍为基本形状a及其所有的旋转变化,如图所示:
输入输出要求:
输入文件名为testin.txt,格式如下所示,各数字用空格隔开,各数字表示棋盘格子编号。
2 3 22 23
输出文件名为testout.txt,要求先输出棋盘覆盖结果,再输出未覆盖的格子个数。输出棋盘用21行21列数字/字母表示,其中0表示未覆盖的格子,1表示障碍,字母表示对应方块编号(字母对应关系见“可选方块”一节)。最后输出未覆盖格子个数。这里以6行10列棋盘举例示意输出格式(注意:实际输出应该是21行21列,对应方块形状用对应的字母表示):
要求:
1、 用所提供的方块尽可能覆盖棋盘并输出结果;
2、 在(1)的基础上,棋盘上的空格越少越好。
交付件要求:
C/C++:需要提交可执行文件和压缩打包的源代码工程
JAVA:需要提交压缩打包的整个编码工程目录
构造法说起来也很简单,首先利用对称性和可旋转性,将输入缩减为一种(这里都缩减为),之后对输入的位置进行考虑:
若位于左上角,则可以通过如下的方式填充:
剩余的空格就是左上的第一个格子,剩下的21x16区域用长条可以完美填充
(右下角也是完全一样)
若不位于左上角或右下角,则可通过加入两个L,变成或
的4x3的障碍。将障碍体积变为4x3后,再用长条填充,可以保证填充至只剩1个格子。
被别人一点拨,感觉真的是醍醐灌顶,如此简易的分析方法自己便就是做不到口牙……!
照着这个思路,自己也大致写了下代码:
#include <stdlib.h>
#include <memory.h>
#define TABLE_SIZE 21
// store the input
int input [ 4 ] = { 0 } ;
// store the hole answer
char table [TABLE_SIZE * TABLE_SIZE ] ;
bool isVertical = false ;
void Initialize ( ) ;
void Output ( FILE * f ) ;
void Construct ( ) ;
int main ( ) {
FILE * fw = fopen ( "testout.txt", "w" ) ;
FILE * fp = fopen ( "testin.txt", "r" ) ;
if ( !fp ) {
printf ( "file not found!\n" ) ;
return 0 ;
}
// main loop
while ( ! feof (fp ) ) {
fscanf (fp, "%d %d %d %d", &input [ 0 ], &input [ 1 ], &input [ 2 ], &input [ 3 ] ) ;
Initialize ( ) ;
Construct ( ) ;
Output (fw ) ;
}
fclose (fp ) ;
fclose (fw ) ;
return 0 ;
}
void Initialize ( ) {
int i, j, x, y ;
memset (table, 'f', sizeof (table ) ) ;
for (i = 0 ; i < 4 ; ++i ) {
if (input [i ] < 1 || input [i ] > TABLE_SIZE * TABLE_SIZE ) {
printf ( "input number error!\n" ) ;
exit ( 0 ) ;
}
--input [i ] ; // input pos start from 1... but I start from 0
}
//sort input
for (i = 1 ; i < 4 ; ++i ) {
if (input [i ] < input [i - 1 ] ) {
int temp = input [i ] ;
for (j = i - 1 ; j >= 0 && input [j ] > temp ; --j ) {
input [j + 1 ] = input [j ] ;
}
input [j + 1 ] = temp ;
}
}
//rotate input to 3x2 if it is 2x3
if (input [ 1 ] - input [ 0 ] ! = 1 ) {
isVertical = true ;
for (i = 0 ; i < 4 ; ++i ) {
x = input [i ] % TABLE_SIZE ;
y = input [i ] / TABLE_SIZE ;
input [i ] = x * TABLE_SIZE + TABLE_SIZE - 1 - y ;
}
input [ 0 ] ^ = input [ 1 ] ;
input [ 1 ] ^ = input [ 0 ] ;
input [ 0 ] ^ = input [ 1 ] ;
}
}
void Construct ( ) {
int i, j, x, y ;
x = input [ 0 ] % TABLE_SIZE ;
y = input [ 0 ] / TABLE_SIZE ;
if (input [ 0 ] == 1 || input [ 0 ] == TABLE_SIZE * TABLE_SIZE - 2 - TABLE_SIZE ) { // in the corner (left-top or right-bottom)
if (input [ 0 ] == 1 ) {
table [ 0 ] = '0' ;
} else {
table [TABLE_SIZE * TABLE_SIZE - 1 ] = '0' ;
}
for (i = 1 ; i < TABLE_SIZE ; ++i ) {
table [i + y * TABLE_SIZE ] = 'a' ;
table [i - 1 + (y + 1 ) * TABLE_SIZE ] = 'a' ;
}
} else {
//fill it with L in a 4x3 tiny block (3x4 is also useful)
if (y ! = TABLE_SIZE - 2 && x ! = 1 ) {
for (i = x - 2 ; i < x + 2 ; ++i ) {
for (j = y ; j < y + 3 ; ++j ) {
table [i + j * TABLE_SIZE ] = 'c' ;
}
}
} else {
for (i = x - 1 ; i < x + 3 ; ++i ) {
for (j = y - 1 ; j < y + 2 ; ++j ) {
table [i + j * TABLE_SIZE ] = 'c' ;
}
}
}
//leave a hole anywhere
if (table [ 0 ] == 'f' ) {
table [ 0 ] = '0' ;
} else {
table [TABLE_SIZE - 1 ] = '0' ;
}
}
// fill the barrier
for (i = 0 ; i < 4 ; ++i ) {
table [input [i ] ] = '1' ;
}
}
void Output ( FILE * fp ) {
int i, j ;
for (i = 0 ; i < TABLE_SIZE ; ++i ) {
for (j = 0 ; j < TABLE_SIZE ; ++j ) {
if (isVertical ) {
fprintf (fp, "%c ", table [TABLE_SIZE - 1 - i + j * TABLE_SIZE ] ) ;
} else {
fprintf (fp, "%c ", table [i * TABLE_SIZE + j ] ) ;
}
}
fprintf (fp, "\n" ) ;
}
fprintf (fp, "1\n" ) ;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TABLE_SIZE 21
char table[TABLE_SIZE*TABLE_SIZE];
int input[4] = {0};
bool isVertical = false;
int Initialize()
{
int i,j;
unsigned int Xaxis,Yaxis;
char chTmp = 0;
//首先全部初始化为'f'
memset(table, 'f', sizeof(table));
//检查输入合法性,并将输入都减1,起始为0
for (i = 0; i < 4; ++i){
if (input[i] < 1 || input[i] > TABLE_SIZE * TABLE_SIZE){
printf("input number error!\n");
return -1;
}
--input[i];
}
//升序排列
for (i = 0;i < 3;i++){
for (j = i+1;j < 4;j++){
if (input[i] > input[j]){
chTmp = input[i];
input[i] = input[j];
input[j] = chTmp;
}
}
}
//若障碍是2x3,则旋转成3x2
if (input[1] - input[0] == TABLE_SIZE){
isVertical = true;
for (i = 0;i < 4;i++){
Xaxis = input[i] % TABLE_SIZE;
Yaxis = input[i] / TABLE_SIZE;
input[i] = Xaxis * TABLE_SIZE + TABLE_SIZE - Yaxis - 1;
}
input[0] ^= input[1];//交换input[0]和input[1]的位置
input[1] ^= input[0];
input[0] ^= input[1];
}
return 0;
}
void Construct()
{
unsigned int Xaxis = input[0] % TABLE_SIZE;
unsigned int Yaxis = input[0] / TABLE_SIZE;
int i,j;
//首先处理位于左上角和右下角的情况
if (input[0] == 1 || input[0] == (TABLE_SIZE-1)*TABLE_SIZE-2){
if (input[0] == 1)//标示出未覆盖的地方
table[0] = '0';
else
table[TABLE_SIZE*TABLE_SIZE-1] = '0';
for (i = 1;i < TABLE_SIZE;i++){
table[Yaxis*TABLE_SIZE+i] = 'a';
table[(Yaxis+1)*TABLE_SIZE+i-1] = 'a';
}
}
//障碍物位于最上一行,左侧填充g,右侧填充c
else if (Yaxis == 0){
table[TABLE_SIZE*TABLE_SIZE-1] = '0';
table[input[0]-1] = 'g';
table[input[0]-2] = 'g';
table[input[0]+TABLE_SIZE-2] = 'g';
table[input[0]+TABLE_SIZE*2-2] = 'g';
table[input[0]+TABLE_SIZE+1] = 'c';
table[input[0]+TABLE_SIZE*2-1] = 'c';
table[input[0]+TABLE_SIZE*2] = 'c';
table[input[0]+TABLE_SIZE*2+1] = 'c';
}
//障碍物位于最下一行,左侧填充g,右侧填充c
else if (Yaxis == TABLE_SIZE-2){
table[0] = '0';
table[input[0]-TABLE_SIZE+2] = 'g';
table[input[0]+2] = 'g';
table[input[0]+TABLE_SIZE+1] = 'g';
table[input[0]+TABLE_SIZE+2] = 'g';
table[input[0]-1] = 'c';
table[input[0]-TABLE_SIZE] = 'c';
table[input[0]-TABLE_SIZE-1] = 'c';
table[input[0]-TABLE_SIZE+1] = 'c';
}
//障碍物位于中间,周围填充c
else{
table[TABLE_SIZE*TABLE_SIZE-1] = '0';
for (i = 0;i < 3;i++){
for (j = 0;j < 4;j++){
table[(Yaxis+i-1)*TABLE_SIZE+Xaxis+j-1] = 'c';
}
}
}
//标示出障碍物的位置
for (i = 0;i < 4;i++){
table[input[i]] = '1';
}
}
void Output(FILE* fp)
{
int i,j;
for (i = 0; i < TABLE_SIZE; ++i){
for (j = 0; j < TABLE_SIZE; ++j){
if (isVertical){
fprintf(fp, "%c ", table[TABLE_SIZE - 1 - i + j * TABLE_SIZE]);
}else{
fprintf(fp, "%c ", table[i * TABLE_SIZE + j]);
}
}
fprintf(fp, "\n");
}
fprintf(fp, "1\n");
}
int main()
{
FILE *fI,*fO;
fI = fopen("testin.txt","r");
if (!fI)
{
printf("testin.txt does not exist!\n");
return -1;
}
fO = fopen("testout.txt","w");
fscanf(fI,"%d %d %d %d", &input[0], &input[1], &input[2], &input[3]);
if (Initialize())
{
printf("Initialize failed!\n");
return -1;
}
Construct();
Output(fO);
fclose(fO);
fclose(fI);
return 0;
}