有一张 H 行 W 列的房间地图。 地图的每个格子是 .(空格)、#(墙)或 S(机器人起始所在的空格)之一,S 恰好有一个。 机器人从前往后逐个字符执行由 U(上)、D(下)、L(左)、R(右)组成的命令字符串。 每条命令让机器人朝那个方向移动一格。 如果移动到的格子在地图外或是墙,机器人退回到移动前的那一格,碰撞次数加 1。 执行完所有命令后,在一行中输出机器人所在格子的行号、列号(都从 1 开始数)和碰撞次数,用一个空格隔开。 试着把位置做成有行、列两个成员的结构体,并写一个原地移动一格的函数(或方法)。 每条命令移动之前先用 prev = cur 保存位置,被挡住时用 cur = prev 恢复。
输入
第一行给出 H 和 W,接下来 H 行每行给出地图的一行(长度 W,没有空格),最后一行给出命令字符串。 1 ≤ H, W ≤ 100,命令字符串长度为 1 到 100,000。
输出
一行:"行 列 碰撞次数"
样例 1 · stdin
3 4
S..#
.#..
....
RRRDDLLUR
stdout
2 1 2
main.py
错误列表00F8 ↓ · ⇧F8 ↑
输入(stdin)
运行时这些行会依次作为 input()/标准输入传入(运行中不会等待输入)。
$ 就绪
请在电脑上打开以编写和运行代码。在手机上可以查看题目和题解。
其他语言怎么写?查看各语言题解 · 3 种语言题解
本题只接受 C、C++ 和 C#。 能自己定义赋值时整体复制数据的值类型结构体的就是这三种;Python、JavaScript、TypeScript、Java 的对象和 Craykon 的 字典() 赋值后是指向同一个东西的引用(这些语言要新建元组或新对象来恢复)。 C、C++ 的 Point prev = cur; 以及 C# struct Point 的 prev = cur,得到的是复制了行列的独立值,之后原地移动 cur,prev 也保持不变。 C 为了原地移动,用 void step(Point *p, char d) 这样的指针接收,写 p->r--,调用时写 step(&cur, d)。 C++ 和 C# 由成员函数(方法)修改对象自身。 四个陷阱:① 在 C# 中把 struct 改成 class,prev = cur 只是多了一个指向同一对象的引用,移动时 prev 跟着动,cur = prev 什么也恢复不了。 不报任何错,机器人就走进墙里。 ② 在 C 中像 Point *prev = &cur; 这样拿地址,也是同样的结果。 ③ 在 C++ 中用引用 Point &prev = cur;,prev 也只是 cur 的别名。 ④ 在 C 中像 void step(Point p, char d) 这样按值接收,则正好相反:只有副本在动,机器人一直停在起始格。
C#Main.cs · 43 行
using System;struct Point // 값 타입: 대입하면 R, C가 통째로 복사된다{ public int R, C; public void Step(char d) { if (d == 'U') R--; else if (d == 'D') R++; else if (d == 'L') C--; else C++; }}class Program{ static void Main() { string[] t = Console.In.ReadToEnd().Split((char[])null, StringSplitOptions.RemoveEmptyEntries); int h = int.Parse(t[0]), w = int.Parse(t[1]); string[] grid = new string[h]; var cur = new Point(); for (int r = 0; r < h; r++) { grid[r] = t[2 + r]; int c = grid[r].IndexOf('S'); if (c >= 0) cur = new Point { R = r, C = c }; } string moves = t[2 + h]; int bumps = 0; foreach (char d in moves) { Point prev = cur; // struct라서 복사본이 따로 생긴다 cur.Step(d); if (cur.R < 0 || cur.R >= h || cur.C < 0 || cur.C >= w || grid[cur.R][cur.C] == '#') { cur = prev; bumps++; } } Console.WriteLine($"{cur.R + 1} {cur.C + 1} {bumps}"); }}
C++main.cpp · 39 行
#include <iostream>#include <string>#include <vector>struct Point { int r = 0, c = 0; void step(char d) { // 멤버 함수는 자기 자신(this)을 제자리에서 바꾼다 if (d == 'U') r--; else if (d == 'D') r++; else if (d == 'L') c--; else c++; }};int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int h, w; std::cin >> h >> w; std::vector<std::string> grid(h); Point cur; for (int r = 0; r < h; r++) { std::cin >> grid[r]; auto c = grid[r].find('S'); if (c != std::string::npos) cur = {r, static_cast<int>(c)}; } std::string moves; std::cin >> moves; int bumps = 0; for (char d : moves) { Point prev = cur; // 값 복사: prev는 cur와 상관없는 따로 있는 Point cur.step(d); if (cur.r < 0 || cur.r >= h || cur.c < 0 || cur.c >= w || grid[cur.r][cur.c] == '#') { cur = prev; bumps++; } } std::cout << cur.r + 1 << ' ' << cur.c + 1 << ' ' << bumps << '\n';}
Cmain.c · 40 行
#include <stdio.h>#include <string.h>typedef struct { int r, c;} Point;static char grid[100][101];static char moves[100001];/* 원본을 제자리에서 움직이려면 포인터로 받는다 */void step(Point *p, char d) { if (d == 'U') p->r--; else if (d == 'D') p->r++; else if (d == 'L') p->c--; else p->c++;}int main(void) { int h, w; scanf("%d %d", &h, &w); Point cur = {0, 0}; for (int r = 0; r < h; r++) { scanf("%100s", grid[r]); char *s = strchr(grid[r], 'S'); if (s) cur = (Point){r, (int)(s - grid[r])}; } scanf("%100000s", moves); int bumps = 0; for (int i = 0; moves[i]; i++) { Point prev = cur; /* 구조체 대입: r, c가 통째로 복사된 따로 있는 값 */ step(&cur, moves[i]); if (cur.r < 0 || cur.r >= h || cur.c < 0 || cur.c >= w || grid[cur.r][cur.c] == '#') { cur = prev; /* 저장해 둔 복사본으로 되돌린다 */ bumps++; } } printf("%d %d %d\n", cur.r + 1, cur.c + 1, bumps); return 0;}