题目描述:
这里引用刘汝佳先生所著的《算法竞赛入门经典(第二版)》中对本题目的中文翻译:
有一个5×5的网格,其中恰好有一个格子是空的,其他格子各有一个字母,一共有四种指令:A,B,L,R,分别表示把空格上、下、左、右的相邻字母移到空格中。输入初始网格和指令序列(分别以数字0结束),输出指令执行完毕后的网格。如果有非法指令,应输出"This puzzle has no final configuration.",例如,图执行ARRBBL0后,效果如图所示:
题目分析:
坦率地讲,这道题虽看起来很复杂,但其实本质上就是对数组中的元素按要求进行交换。思路上也没什么奇思妙想,就按照题目要求的一步一步来就可以。读一个指令,先判断是否越界,然后交换元素或是退出循环给出报错提示。在我看里,值得注意的地方两点:
- 输出格式需要注意一下。原题中 Separate output from different puzzle records by one blank line 是指在每两个 puzzle 之间空一行,换句话说就是最后一行不空行。
- 在输入这方面,原题有写 This sequence of moves may be spread over several lines, but it always ends in the digit 0 即:移动步骤可能被分为多行,但是总以 0 结尾。所以就可能出现类似的情况:

关键字: 数组,字符串,判断,元素交换
AC代码:
#include <iostream>
#include <string>
#define ROW 5
#define COL 5
using namespace std;
int main()
{
int kase = 1;
while( true )
{
char puzzle[ROW][COL];
string str, moves;
int isBreak = 0, isFail = 0, blank_row = 0, blank_col = 0;
// 读取 puzzle
for(int i = 0; i < ROW; i++)
{
getline(cin, str);
if(str[0] == 'Z')
{ // 判断是否为结束符
isBreak = 1;
break;
}
for(int j = 0; j < COL; j++)
{
puzzle[i][j] = str[j];
if(str[j] == ' ')
{ // 记录空格位置
blank_row = i;
blank_col = j;
}
}
}
if(isBreak) break;
do
{ // 读取 moves
string subMoves;
getline(cin, subMoves);
moves += subMoves;
} while(moves[moves.length()-1] != '0');
for(int i = 0; i < moves.length(); i++)
{
if(moves[i] == 'A')
{
if(blank_row - 1 < 0)
{
isFail = 1;
break;
}
else
{
// 元素交换
char tmp = puzzle[blank_row-1][blank_col];
puzzle[blank_row-1][blank_col] = puzzle[blank_row][blank_col];
puzzle[blank_row][blank_col] = tmp;
blank_row--; // 空格位置更新
}
}
if(moves[i] == 'B')
{
if(blank_row + 1 > 4)
{
isFail = 1;
break;
}
else
{
char tmp = puzzle[blank_row+1][blank_col];
puzzle[blank_row+1][blank_col] = puzzle[blank_row][blank_col];
puzzle[blank_row][blank_col] = tmp;
blank_row++;
}
}
if(moves[i] == 'L')
{
if(blank_col - 1 < 0)
{
isFail = 1;
break;
}
else
{
char tmp = puzzle[blank_row][blank_col-1];
puzzle[blank_row][blank_col-1] = puzzle[blank_row][blank_col];
puzzle[blank_row][blank_col] = tmp;
blank_col--;
}
}
if(moves[i] == 'R')
{
if(blank_col + 1 > 4)
{
isFail = 1;
break;
}
else
{
char tmp = puzzle[blank_row][blank_col+1];
puzzle[blank_row][blank_col+1] = puzzle[blank_row][blank_col];
puzzle[blank_row][blank_col] = tmp;
blank_col++;
}
}
if(moves[i] == '0') break;
}
if(kase >= 2) cout << endl;
cout << "Puzzle #" << kase++ << ":\n";
if(isFail) cout << "This puzzle has no final configuration.\n";
else
{
for(int i = 0; i < ROW; i++)
{
for(int j = 0; j < COL-1; j++)
cout << puzzle[i][j] << ' ';
cout << puzzle[i][COL-1] << endl;
}
}
}
return 0;
}

缺点与不足
代码中有许多功能相近的重复部分(例如元素交换部分),因时间缘故未封装成函数,导致代码有些臃肿,模块化程度低。
这篇博客详细介绍了UVA 227 'Puzzle'问题,这是一个涉及5x5网格和四种移动指令的挑战。博主分析了问题本质,指出其为数组元素交换,并提供了AC代码实现。同时,指出了代码中重复部分未封装的不足,强调了输出格式和输入处理的细节。


986

被折叠的 条评论
为什么被折叠?



