紫书刷题进行中,题解系列点这里
习题3-5 UVA227 Puzzle(50行AC代码)
思路分析
给定一个5*5的字母拼图(A-X),包含一个空格,再给定移动序列,以0表示结束,求最终的拼图,若非法则输出相应提示信息。
读入拼图后,先找出空格位置,再根据移动序列移动即可。
注意点
- 输入时getline可读入换行并丢弃它,cin遇到换行立即停止,不会丢弃,即下一个读取依旧是换行
- 输出时两个puzzle间需有空行,最后一个puzzle不需要
- 输入样例测试时,直接复制测试样例会导致第五列空格缺失,需自己补上
AC代码(C++11,简单模拟,复杂输入输出)
#include<bits/stdc++.h>
using namespace std;
string puzzle[5], s;
int cnt = 0, x, y, x2, y2, dict[4][2] = {{-1,0}, {1,0}, {0,-1}, {0,1}}; // 上下左右偏移
map<char, int> mp{{'A',0}, {'B',1}, {'L',2}, {'R',3}}; // 字符映射到数字
bool isLegal = true, isOver = false; // 当前拼图是否有合法结果,是否结束
int main() {
while(getline(cin,puzzle[0])) {
if (puzzle[0][0] == 'Z') break;
for (int i = 1; i < 5; i ++) getline(cin,puzzle[i]); // getline可读入空格
for (int i = 0; i < 5; i ++) { // 找空格位置
for (int j = 0; j < 5; j ++) { // 寻找空格坐标
if(puzzle[i][j] == ' ') {
x = i; y = j;
break;
}
}
}
isOver = false; isLegal = true; // 初始化
while(true) {
cin >>s; getchar(); // 注意吸收换行
for (auto ch : s) {
if (ch == '0') { // 当前拼图结束
isOver = true; // 标记结束
if (cnt >= 1) printf("\n"); // 两个输出之间需有空行
printf("Puzzle #%d:\n", ++cnt);
if (isLegal) { // 合法输出
for (int i = 0; i < 5; i ++) {
for (int j = 0; j < 5; j ++) {
printf("%c%c", puzzle[i][j], (j == 4) ? '\n' : ' ');
}
}
}
else printf("This puzzle has no final configuration.\n");
}
else {
x2 = x + dict[mp[ch]][0];
y2 = y + dict[mp[ch]][1];
if (x2 >= 0 && x2 < 5 && y2 >= 0 && y2 < 5) { // 是否合法
swap(puzzle[x][y], puzzle[x2][y2]); // 交换
x = x2; y = y2; // 更新x,y
}
else isLegal = false; // 非法
}
}
if (isOver) break; // 跳出循环
}
}
return 0;
}