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;}