兰顿蚂蚁


兰顿蚂蚁

题目描述

img

算法设计

关键词:模拟

输入处理

  1. 地图存入n行m列的数组A[n][m];
  2. 坐标存入point[2];
  3. 方向dir;
  4. 步数step;

代码如下:

    //输入处理
    int m, n;//m行n列
    scanf("%d%d", &m, &n);
    int map[m][n];
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            scanf("%d", &map[i][j]);
        }
    }
    int point[2];
    scanf("%d%d", &point[0], &point[1]);
    char dir;
    scanf("%c", &dir);
    int step;
    scanf("%d", &step);

实操时发现创建一个变量currDir表示当前方向,*dir表示所有方向会更方便

修改为:

    char curDir;
    char dir[4] = {'U', 'R', 'D', 'L'};
    scanf("%c", &carDir);

这样就可以通过dir下标的加减实现方向的改变了

但这时又出现了新的问题:

​ 当curDir=‘L’时,若刚好为=需要右转(即下标+1)则会出现数组下标越界的情况。

所以我们可以设置两个“缓冲量”:

char dir[6] = {'L','U', 'R', 'D', 'L','U'};

循环调用时下标从1到4即可。

故:

  1. 对于“模拟”类型的问题设置一个“当前量”可以方便问题求解
  2. 数组下标越界可以通过设置“缓冲量”来解决

算法逻辑

核心:模拟蚂蚁的行为

  1. 根据蚂蚁所在格子类型改变方向和格子类型:
char changeDir(const int *point, int **map, char curDir, const char *dir) {
    int type = map[point[0]][point[1]];
    //转向
    for (int i = 1; i < 5; ++i) {
        if (curDir == dir[i] && type) {
            curDir = dir[i + 1];
            break;
        } else if (curDir == dir[i] && !type) {
            curDir=dir[i-1];
        }
    }
    map[point[0]][point[1]]=!type;
    return curDir;
}
  1. 根据方向改变坐标:

    void changePoint(int *point, char curDir) {
        switch (curDir) {
            case 'U':
                point[1]+=1;
                break;
            case 'R':
                point[0]+=1;
                break;
            case 'D':
                point[1]-=1;
                break;
            case 'L':
                point[0]-=1;
                break;
            default: {
            }
        }
    }
    
  2. 循环调用函数且step++:

        int curStep=0;
        do{
            changeDir(point, (int **) map, curDir, dir);
            curStep++;
        } while (curStep!=step);
    }
    

    这里使用了当型循环,用for也一样。

输出处理

printf("%d %d",point[0],point[1]);

测试运行

。。。。

司空见惯了,找问题吧


原来是忘记调用changeDir函数了,立即修改:

    int curStep = 0;
    do {
        changePoint(point, curDir);
        curDir = changeDir(point, (int **) map, curDir, dir);
        curStep++;
    } while (curStep != step);

再次测试~

呃。。。。

继续找吧,小事。

在适当位置增加输出语句进行调试:

  1. 输入测试:

        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                printf("%d ",map[i][j]);
            }
            printf("\n");
        }
        printf("%d %d %c %d",point[0],point[1],curDir,step);
    

    结果:

    image-20211201223527275

    立马找到了问题所在:

    1. curDir扫描失败:缓冲区里的空格赋值给了curDir,这是个老问题了。
    scanf("%c", &curDir);
    

    解决:**%c前加空格忽略缓冲区中的空白字符**

    scanf(" %c", &curDir);
    
    1. step扫描失败:遇到了‘L’这个非法字符导致扫描停止。

​ 修改后再次运行:

​ 输入没问题了,但结果还是有问题

​ 下面测试changeDir函数

char changeDir(const int *point, int **map, char curDir, const char *dir) {
    int type = map[point[0]][point[1]];
    printf("type=%d ",type);
    //转向
    for (int i = 1; i < 5; ++i) {
        if (curDir == dir[i] && type) {
            curDir = dir[i + 1];
            break;
        } else if (curDir == dir[i] && !type) {
            curDir = dir[i - 1];
        }
    }
    map[point[0]][point[1]] = !type;
    printf("curDir=%c ",curDir);
    return curDir;
}

​ 运行发现没有输出,说明没有调用该函数,而changePoint应该不会出问题,那么问题很可能 出在二维数组map的调用上。

​ 新增一个列指针p,通过列指针p来实现二维数组map的调用

​ 定义及初始化:

int *p;
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            scanf("%d", &map[i][j]);
        }
    }
    p = map[0];
char changeDir(const int *point, int *p, int n, char curDir, const char *dir) {
    int type = *(p + point[0] * n + point[1]);
    printf("type=%d ", type);
    //转向
    for (int i = 1; i < 5; ++i) {
        if (curDir == dir[i] && type) {
            curDir = dir[i + 1];
            break;
        } else if (curDir == dir[i] && !type) {
            curDir = dir[i - 1];
        }
    }
    *(p + point[0] * n + point[1]) = !type;
    printf("curDir=%c ", curDir);
    return curDir;
}

运行发现终于出结果了:

仔细一看怎么不对,答案是1,3

那应该是移动也就是changePoint出了问题

果然,题目中point[0]、point[1]分别表示行和列,而在函数中我因为习惯将其当成了坐标进行计算

void changePoint(int *point, char curDir) {
    switch (curDir) {
        case 'U':
            point[1] += 1;
            break;
        case 'R':
            point[0] += 1;
            break;
        case 'D':
            point[1] -= 1;
            break;
        case 'L':
            point[0] -= 1;
            break;
        default: {
        }
    }
}

修改后:

void changePoint(int *point, char curDir) {
    switch (curDir) {
        case 'U':
            point[0] -= 1;
            break;
        case 'R':
            point[1] += 1;
            break;
        case 'D':
            point[0] += 1;
            break;
        case 'L':
            point[1] -= 1;
            break;
        default: {
        }
    }
}

再次运行:

得到了正确的结果

开开心心提交:

。。。

对了但没完全对,还有一些情况没考虑。

首先,发现在changrDir里少了个brake;

for (int i = 1; i < 5; ++i) {
        if (curDir == dir[i] && type) {
            curDir = dir[i + 1];
            break;
        } else if (curDir == dir[i] && type==0) {
            curDir = dir[i - 1];
        }
    }

改为

for (int i = 1; i < 5; ++i) {
        if (curDir == dir[i] && type) {
            curDir = dir[i + 1];
            break;
        } else if (curDir == dir[i] && type==0) {
            curDir = dir[i - 1];
            break;
        }
    }

运行发现样例结果错了,说明之前的样例通过是个巧合。

然后主方法用do-while会导致计数困难,还是使用fori

    for (int i = 0; i < step; ++i) {
        changePoint(point,curDir);
        curDir= changeDir(point,p,n,curDir,dir);
    }

运行:

在changDir处加入输出语句,输出point坐标和该位置改变后的值

找到问题是应该先调用changeDir函数。犯这个错误的原因是一开始以为需要先走后改变方向。

    for (int i = 0; i < step; ++i) {
        changePoint(point,curDir);
        curDir= changeDir(point,p,n,curDir,dir);
    }

修改后:

    for (int i = 0; i < step; ++i) {
        curDir= changeDir(point,p,n,curDir,dir);
        changePoint(point,curDir);
    }

样例输出正常,再次提交:

终于迎来了胜利!

总结

  1. 模拟类题目需定义一套“当前量”来表示模拟对象当前的状态
  2. 数组下标可能越界时可设置几个缓冲量
  3. 思考二维数组还是以“i行j列”的形式进行
  4. 当二维数组行和列长度为变量时,想要作为实参传递需要定义列指针*p,*p=a[0];,将*p和列长n作为实参传入函数

文章作者: 喵寒
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 喵寒 !
评论
  目录