XTU-OJ 1454-轨迹

题目描述#

一个机器人会接收行动的指令,请绘制它的移动轨迹。 使用_ 表示横线,| 表示竖线,要求图形的每行行尾无多余的空格。

注意!!! 如果同一格有横竖两种轨迹,画竖线

指令格式为 d n,表示按方向d移动n步。方向为LRUD,依次为左右上下。

比如依次执行R 2, U 3, L 5, D 7, R 11五条指令时,轨迹图如下:

 _____
|     |
|     |
|   __|
|
|
|
|___________

输入格式#

第一行是一个整数n(1≤n≤10000),表示指令的条数。 以后的n行,每行一条指令。

输出格式#

按格式要求输出轨迹图。

题目保证轨迹图的宽与高不会超过600。

样例输入#

4
L 1
U 1
R 1
D 1

样例输出#

 _
|_|

解题思路:这题可能是今年OJ中Top 5的题了,因为它的轨迹行走,图形打印都有很多的限定条件,而题目也没有仔细说明,全要靠我们自己去看样例或者试错去挖掘。这题难点就在这儿了。 下面我们来看看有哪些需要避坑和注意的点。

后面想了下,说了这么多,画了这么几个模糊的图,还不如让你们运行下面的代码,去看看是怎么输出的。(/流汗)

1.  题目保证 “轨迹图的宽与高不会超过600”,但轨迹怎么走是无法预测的,所以要申请一个保证能存下轨迹图的数组—— maps[1210][1210], 起点从 stx = 601,sty = 601 开始,这样上下左右都留了 600个位置。

2. 因为起点在数组中心位置,所以不可能再从 第1行,第1列 一直输出到 第1210行,第1210列。因此我们需要定义几个标记变量——ups,downs,lefts,分别记录轨迹图的 上下左 边界。 另外题目又要求:每行行尾无多余的空格。 所以每行的右边界 需要单独记录。 tags[1210] 数组的作用就是记录每一行的右边界。 tags[603] = 610,表示第603行,第610列之后就不用再输出了。

3. 每一步指令执行结束后,轨迹点停留的坐标(stx,sty) 在最后一步的下一格。比如28行:for (int i = 0; i < n; i ++, sty --),在向左已经走完了之后,最后还有执行 sty -- (左移一格)  ~~~~   而边框坐标,定为 最后一步所在格子的坐标。 比如 向左走肯定要判定是否更新左边界:if (sty < lefts)   lefts = sty+1;   向下走了要判定是否更新下边界:if (stx > downs)   downs = stx-1;

如图:  各个方向,最后坐标点都停留在该方向的下一格(紫色符号),但是边框还是记录的最后一个符号的位置。

4. 当前指令和上一个指令方向相反时。符号输入不再从 “下一格”开始输入了,而是从 “最后一步” 所在的位置原路返回。

5.  当前指令和上一个指令方向不相反时。#1 当  上一个指令是 向左/右 ,@1 当前指令为向右/左或向上时,直接从当前坐标的开始 打印;@2  当前指令为向下时,需要额外把sty向下移一格。#2当  上一个指令是 向下 ,当前指令为向下时,不需要额外处理, @3 当前指令为 向左/右 时,stx要上移一格,然后sty 向左/右 移一格。  #3 当  上一个指令是 向上 ,当前指令为向上时,不需要额外处理,@4 当前指令为 向左/右 时,sty 向左/右 移一格。

具体对照代码中 *1、*2、*3 注释

6.  因为第3点,我们定义的边框是每个指令走的最后一步的坐标,但如果像 在一个向左指令结束完之后,后面接了一个向上/下的指令,如上图的@1 @2,那么左边界应该再向左移一格,所以在每个指令之中,还需要判断一下(其他情况同理),详情对比代码注释  !A!  和 !B!   /  !C! 向下是个特别的情况,不需要再额外考虑。

结语:考虑完上述几个情况,本题也就差不多出来了(内容写的有点多,逻辑上可能有点乱,等我慢慢改吧)怎么说呢,大模拟题,别人的代码你能看懂就看看,看不下去的直接CV吧。在看完题解之后,还是要在脑中 把n步指令一次性 完全且无差错地模拟出来才行。模拟题要自己理清之后才能算是自己的。

AC代码:

#include <stdio.h>
 
int N,n;
char d,p;
int ups,downs,lefts,stx,sty;
int tags[1210];                          //  右边框坐标
char maps[1210][1210];
 
void drawmaps()
{
    p = 'V';
    stx = 601,sty = 601;                   //  stx为行,sty为列
    ups = 601,downs = 601,lefts = 601;     //  上/下/左 边框极限坐标, 
    for (int i = 0; i < 1210; i ++)        //  所有元素先默认都为 ' '(空格)
        for (int j = 0; j < 1210; j ++)
            maps[i][j] = ' ';
}

void draw(char d,int n)
{
    if  (d == 'L')
    {
        if (p == 'R')   sty --;                     // *1;如果上一步是向右,这步要先往左退一格
        if (p == 'D')   stx --;                     // *2;如果上一步是向下,这步应该在同一行左移
        if (p == 'U' || p == 'D')   sty --;         // *3;如果上一步是向上/下,这步起始位置要往左移一步
        if (stx < ups)       ups = stx;             // !B!  如果比ups更高,要重新更新。
        if (tags[stx] < sty)    tags[stx] = sty;
        for (int i = 0; i < n; i ++, sty --)        // 如果这点已经有'|'了,就不能打印'_'   '|'优先级更高
            if (maps[stx][sty] != '|')
                maps[stx][sty] = '_';

        if (sty < lefts)       lefts = sty+1;       // !A! 默认最后的'_'是当前轨迹图最左边的的符号
    }

    else if (d == 'R')
    {
        if (p == 'L')   sty ++;                     // *1;如果上一步是向左,这步要先往右退一格
        if (p == 'D')   stx --;                     // *2
        if (p == 'U' || p == 'D')   sty ++;         // *3
        if (stx < ups)       ups = stx;             // !B!  
        for (int i = 0; i < n; i ++, sty ++)
            if (maps[stx][sty] != '|')
                maps[stx][sty] = '_';
    
        if (tags[stx] < sty)    tags[stx] = sty-1;  
    }
    else if (d == 'U')
    {
        if (p == 'D')   stx --;                  // *1;如果上一步是向下,这步开始前要往上退一格
        if (sty < lefts)   lefts = sty;          // !A!(32行)  如果'|'的位置比lefts还小,要重新更新

        for (int i = 0; i < n; i ++, stx --)
        {
            maps[stx][sty] = '|';
            if ( tags[stx] < sty)
                tags[stx] = sty;
        }
        if (stx < ups)       ups = stx+1;       // !B! 默认最后的'|' 所在位置是轨迹图最高位。
    }
    else if (d == 'D')
    {
        if (p == 'U')   stx ++;                 // *1;如果上一步是向上,这步开始前要先往下退一格
        if (p == 'L' || p == 'R')   stx ++;     // *3;如果上一步是左/右走, 这步要从下一行开始
        if (sty < lefts)   lefts = sty;         // !A!(同理)
        for (int i = 0; i < n; i ++, stx ++)
        {
            maps[stx][sty] = '|';
            if ( tags[stx] < sty)
                tags[stx] = sty;
        }
        if (stx > downs)      downs = stx-1;    // !C! 同理
    }
}

void output()
{
    for (int i = ups; i <= downs; i ++)
    {
        for (int j = lefts; j <= tags[i]; j ++)
            printf("%c",maps[i][j]);
        puts("");
    }
}
int main()
{
    drawmaps();                         // 初始化数组
    scanf("%d",&N);
    for (int i = 1; i <= N; i ++)
    {
        scanf(" %c %d",&d,&n);         // 读入指令,记得%c之前留个 空格
        draw(d,n);                     
        p = d;                         // 记录上一个指令 
    }
    output();
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值