試験問題を解いてみた
人材獲得作戦・4 試験問題ほか: 人生を書き換える者すらいた。
3時間でここまで。全経路をたどってしまうので、Lv3扱いで不合格(^^;
与えられた迷路を、1歩ごとに盤面を新たに生成しながら再帰していく。最初に作るものとしては妥当かと。
しかし、経路をすべて探索してしまうので、1本道だけならそれほどでもないが、広いスペースが存在するととたんに探索数が多くなってしまう。ということでLv3扱い。
#include <stdio.h> #include <string.h> #include <assert.h> #define COLUMN 26 #define LINE 13 typedef struct { int x; int y; } point_t; typedef struct { char c[LINE][COLUMN+1]; } maze_t; point_t direction[4] = { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } }; maze_t min_maze = { "$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$" }; int can_move (maze_t *m, point_t p, int d) { char c = m->c[p.x + direction[d].x][p.y + direction[d].y]; return (c == ' ' || c == 'G'); } int is_goal (maze_t *m, point_t p) { int i; for (i=0; i<LINE; i++) if (m->c[p.x][p.y] == 'G') return 1; return 0; } point_t move_point (maze_t *m, point_t p, int d) { point_t ret; ret.x = p.x + direction[d].x; ret.y = p.y + direction[d].y; return ret; } void set_point (maze_t *m, point_t p, char c) { m->c[p.x][p.y] = c; } int count_path (maze_t *m) { int i, j, s = 0; for (i=0; i<LINE; i++) for (j=0; j<COLUMN; j++) if (m->c[i][j] == '$') s++; return s; } void go_maze (maze_t m, point_t p) { int d, c = count_path (&m); if (is_goal (&m, p)) { if (c < count_path (&min_maze)) min_maze = m; return; } set_point (&m, p, '$'); for (d=0; d<4; d++) { if (can_move (&m, p, d)) { point_t pp = move_point (&m, p, d); go_maze (m, pp); } } } void print_maze (maze_t *m) { int i; for (i=0; i<LINE; i++) printf ("%s\n", m->c[i]); } int main (void) { maze_t question = { "**************************", "*S* * *", "* * * * ************* *", "* * * ************ *", "* * *", "************** ***********", "* *", "** ***********************", "* * G *", "* * *********** * *", "* * ******* * *", "* * *", "**************************" }; maze_t answer = { "**************************", "*S* * $$$ *", "*$* *$$*$ ************* *", "*$* $$* $$$************ *", "*$$$$* $$$$$ *", "**************$***********", "* $$$$$$$$$$$$$ *", "**$***********************", "* $$$$$*$$$$$$$$$$$$$$G *", "* * $$$ *********** * *", "* * ******* * *", "* * *", "**************************" }; point_t start={1,1}; go_maze (question, start); set_point (&min_maze, start, 'S'); printf ("------------------------------\n"); print_maze (&min_maze); { int i; for (i=0; i<LINE; i++) { assert (count_path(&min_maze) == count_path(&answer)); } } return 0; }
さらに30分かけて、無駄な探索をしないように修正。各マスにスタートからの距離を記録しておくことによって実現。これで一応Lv4だけど、1歩ごとに盤面を保存しながら再帰しているので、少し大きくなると動かなくなってしまう。
diff --git a/meiro.c b/meiro.c index 22cb7d7..c6cfc68 100644 --- a/meiro.c +++ b/meiro.c @@ -21,6 +21,35 @@ point_t direction[4] = { +int maze_count[LINE][COLUMN] = { + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, + { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff } +}; + @@ -92,6 +121,12 @@ go_maze (maze_t m, point_t p) void go_maze (maze_t m, point_t p) { int d, c = count_path (&m); if (is_goal (&m, p)) { if (c < count_path (&min_maze)) min_maze = m; return; } + if (c >= maze_count[p.x][p.y]) + { + return; + } + + maze_count[p.x][p.y] = c; set_point (&m, p, '$'); for (d=0; d<4; d++) { if (can_move (&m, p, d)) { point_t pp = move_point (&m, p, d); go_maze (m, pp); } } }
さらに1歩ずつ盤面をコピーしていたのをやめた。各マスのスタートからの距離だけで、次の1歩を求めて進んでいく。再帰のコストが低い言語なら大きな盤面でも大丈夫なはず。
#include <stdio.h> #include <string.h> #include <assert.h> #define COLUMN 26 #define LINE 13 typedef struct { int x; int y; } point_t; typedef struct { char c[LINE][COLUMN+1]; } maze_t; point_t direction[4] = { { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 } }; maze_t question = { "**************************", "*S* * *", "* * * * ************* *", "* * * ************ *", "* * *", "************** ***********", "* *", "** ***********************", "* * G *", "* * *********** * *", "* * ******* * *", "* * *", "**************************" }; maze_t answer = { "**************************", "*S* * $$$ *", "*$* *$$*$ ************* *", "*$* $$* $$$************ *", "*$$$$* $$$$$ *", "**************$***********", "* $$$$$$$$$$$$$ *", "**$***********************", "* $$$$$*$$$$$$$$$$$$$$G *", "* * $$$ *********** * *", "* * ******* * *", "* * *", "**************************" }; int maze_count[LINE][COLUMN] = { { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff }, { 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff } }; int can_move (point_t p, int d) { char c = question.c[p.x + direction[d].x][p.y + direction[d].y]; return (c == ' ' || c == 'G'); } int is_point (point_t p, char c) { int i; for (i=0; i<LINE; i++) if (question.c[p.x][p.y] == c) return 1; return 0; } point_t move_point (point_t p, int d) { point_t ret; ret.x = p.x + direction[d].x; ret.y = p.y + direction[d].y; return ret; } void set_point (point_t p, char c) { question.c[p.x][p.y] = c; } int count_path (maze_t *m) { int i, j, s = 0; for (i=0; i<LINE; i++) for (j=0; j<COLUMN; j++) if (m->c[i][j] == '$') s++; return s; } void print_count (void) { int i, j; for (i=0; i<LINE; i++) { for (j=0; j<COLUMN; j++) printf ("%04x ", maze_count[i][j]); printf ("\n"); } } void go_maze (point_t p) { int d; if (is_point (p, 'G')) return; for (d=0; d<4; d++) { if (can_move (p, d)) { point_t pp = move_point (p, d); if (maze_count[pp.x][pp.y] > maze_count[p.x][p.y] + 1) { maze_count[pp.x][pp.y] = maze_count[p.x][p.y] + 1; go_maze (pp); } } } } void print_maze (maze_t *m) { int i; for (i=0; i<LINE; i++) printf ("%s\n", m->c[i]); } int main (void) { point_t p, pp, start={1,1}, goal={8,22}; int i, d, count; maze_count[start.x][start.y] = 0; go_maze (start); p = goal; count = maze_count[goal.x][goal.y]; do { set_point (p, '$'); count--; for (d=0; d<4; d++) { pp = move_point (p, d); if (count == maze_count[pp.x][pp.y]) break; } p = pp; } while (d != 4 && ! is_point (p, 'S')); set_point (goal, 'G'); print_maze (&question); for (i=0; i<LINE; i++) { assert (count_path(&answer) == count_path(&answer)); } return 0; }
久しぶりに仕事以外でコード書いたな。