对迷宫的移动进行模拟。需要注意的是输入缓冲区残留问题和输出格式问题。
- 输出案例之间隔一个空行,可以使用第一个输出后没有空行,之后的每个输出前都输出空行。这样就保证所有输出之间的空行
- 弃用fflush和gets函数,gets函数无限制的读取,stream指向stdin,fflush函数的行为不确定,而且fflush函数可移植性不好
- 使用自定义flush缓存处理函数。
介绍一下缓冲区
缓冲区又称为缓存,它是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。
为什么要引入缓冲区
比如我们从磁盘里取信息,我们先把读出的数据放在缓冲区,计算机再直接从缓冲区中取数据,等缓冲区的数据取完后再去磁盘中读取,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。
又比如,我们使用打印机打印文档,由于打印机的打印速度相对较慢,我们先把文档输出到打印机相应的缓冲区,打印机再自行逐步打印,这时我们的CPU可以处理别的事情。
现在您基本明白了吧,缓冲区就是一块内存区,它用在输入输出设备和CPU之间,用来缓存数据。它使得低速的输入输出设备和高速的CPU能够协调工作,避免低速的输入输出设备占用CPU,解放出CPU,使其能够高效率工作。
当程序调用getchar()
函数时,程序就等着用户按键,用户输入的字符被存放在键盘缓冲区中,直到用户按回车为止(回车字符也放在缓冲区中)。当用户键入回车之后,getchar()函数才开始从键盘缓冲区中每次读入一个字符。也就是说,后续的getchar()函数调用不会等待用户按键,而直接读取缓冲区中的字符,直到缓冲区中的字符读完后,才重新等待用户按键。
这里说一下,题目第二个样例和第三个样例的输入行的空格显示不出来
#include <cstdio>
#include <cstring>
#include <ctype.h>
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
char maze[5][5];
//标记空格位置
int x, y;
/**
* 将(x1, y1)按dir方向移动
* @prama x1, y1 待移动的空格
* @prama dir 移动方向
* @return 返回是否移动成功
*/
bool move(int x1, int y1, char dir)
{
int nx = x1, ny = y1;
if (dir == 'L')
{
ny--;
}
else if (dir == 'B')
{
nx++;
}
else if (dir == 'A')
{
nx--;
}
else if (dir == 'R')
{
ny++;
}
//检测是否合法
if (nx >= 0 && nx < 5 && ny >= 0 && ny < 5)
{
char tmp;
maze[x1][y1] = maze[nx][ny];
maze[nx][ny] = ' ';
x = nx, y = ny;
return true;
}
else
{
return false;
}
}
void print()
{
_for (i, 0, 5)
{
_for (j, 0, 5)
{
if (j == 0)
{
printf("%c", maze[i][j]);
}
else
{
printf(" %c", maze[i][j]);
}
}
printf("\n");
}
}
/**
* 自定义输入流残存处理函数
*/
void flush()
{
char ch;
while ((ch = getchar()) != '\n' && ch != 'EOF') ;
}
int main()
{
char s[10];
//记录案例个数
int cnt = 0;
while (1)
{
//移动合法为true,反之
bool moveflg = true;
_for (i, 0, 5)
{
fgets(s, 7, stdin);
_for (j, 0, 5)
{
if (s[0] == 'Z')
{
return 0;
}
maze[i][j] = s[j];
if (maze[i][j] == ' ' || maze[i][j] == '\n')
{
maze[i][j] = ' ';
x = i;
y = j;
}
}
}
int ch;
//读入移动方向字符
while ((ch = getchar()) != '0')
{
if (ch == 'A' || ch == 'B' || ch == 'L' || ch == 'R')
{
if (!move(x, y, ch))
moveflg = false;
}
//换行符空格不做处理
}
//清空缓存残留
flush();
if (cnt++) printf("\n");
printf("Puzzle #%d:\n", cnt);
if (moveflg)
{
print();
}
else
{
printf("This puzzle has no final configuration.\n");
}
}
return 0;
}
对于字符串的处理C++string容器比C语言的使用效果更好。C++STL帮助我们简单的完成代码实现。
相对来说,C++输入更方便,输出格式不如C好控制。我们因根据情况选择合适的方法帮助我们解题。
程序设计 = 思维+实现,程序设计希望我们把重心放在思维上,尽量使用C++解题
进阶模板代码,二维几何运算
#include <cstdio>
#include <cstring>
#include <ctype.h>
#include <vector>
#include <string>
#include <iostream>
#include <map>
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
using namespace std;
//二维几何运算类
struct Point
{
int x, y;
Point(int x=0, int y=0):x(x),y(y) {}
};
typedef Point Vector;
Vector operator+ (const Vector& A, const Vector& B) { return Vector(A.x+B.x, A.y+B.y); }
Vector operator- (const Point& A, const Point& B) { return Vector(A.x-B.x, A.y-B.y); }
Vector operator* (const Vector& A, int p) { return Vector(A.x*p, A.y*p); }
Vector operator/ (const Vector& A, int p) { return Vector(A.x/p, A.y/p); }
bool operator== (const Point& a, const Point &b) { return a.x == b.x && a.y == b.y; }
bool operator< (const Point& p1, const Point& p2) { return p1.x < p2.x || (p1.x == p2.x && p1.y < p2.y); }
const int Gsize = 5;
vector<string> grid;
map<char, Vector> DIRS;
Vector epos;
bool valid(const Point& p)
{
return p.x >= 0 && p.y >= 0 && p.x < Gsize && p.y < Gsize;
}
void printGrid()
{
_for (i, 0, Gsize)
{
_for (j, 0, Gsize)
{
if (j)
{
cout << ' ';
}
cout << grid[i][j];
}
cout << endl;
}
}
bool tryMove(char cmd)
{
if (!DIRS.count(cmd)) return false;
Point p = epos + DIRS[cmd];
if (!valid(p)) return false;
swap(grid[p.x][p.y], grid[epos.x][epos.y]);
epos = p;
return true;
}
int main()
{
int t = 1;
string line;
DIRS['A'] = Vector(-1, 0);
DIRS['B'] = Vector(1, 0);
DIRS['L'] = Vector(0, -1);
DIRS['R'] = Vector(0, 1);
while (true)
{
grid.clear();
epos.x = -1, epos.y = -1;
_for (i , 0, Gsize)
{
getline(cin, line);
if (line == "Z")
{
return 0;
}
_for (j, 0, Gsize)
{
if (line[j] == ' ')
{
epos.x = i;
epos.y = j;
}
}
grid.push_back(line);
}
string moves;
while (true)
{
getline(cin, line);
bool end = *(line.rbegin()) == '0';
if (!end) moves.append(line);
else moves.append(line, 0, line.size() - 1);
if (end)
break;
}
bool legal = true;
_for (i, 0, moves.size())
{
if (!tryMove(moves[i]))
{
legal = false;
break;
}
}
if (t > 1) cout << endl;
cout << "Puzzle #" << t++ << ":" << endl;
if (legal) printGrid();
else cout << "This puzzle has no final configuration.\n";
}
return 0;
}