對迷宮的移動進行模擬。需要注意的是輸入緩衝區殘留問題和輸出格式問題。
- 輸出案例之間隔一個空行,可以使用第一個輸出後沒有空行,之後的每個輸出前都輸出空行。這樣就保證所有輸出之間的空行
- 棄用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;
}