Puzzle UVA - 227 二维几何

17 篇文章 2 订阅

对迷宫的移动进行模拟。需要注意的是输入缓冲区残留问题和输出格式问题。

  1. 输出案例之间隔一个空行,可以使用第一个输出后没有空行,之后的每个输出前都输出空行。这样就保证所有输出之间的空行
  2. 弃用fflush和gets函数,gets函数无限制的读取,stream指向stdin,fflush函数的行为不确定,而且fflush函数可移植性不好
  3. 使用自定义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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值