6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

AtCoderで深さ優先探索がどうしてもREしてしまった話

Posted at

##深さ優先探索をやってみたかった
つい最近、AtCoder Typical Contest というものがあることを知りました。

どうやら深さ優先探索など、競技プログラミングをやる上で必要になってくるアルゴリズムのコーディングを練習できるものみたいですね。

↓僕が今回取り組んだのはこちら↓
ATC001

##実際に書いたコード

ATC001のA問題で僕が提出したコードは以下の通りです。

dfs.py
def dfs(px,py):
	if px < 0 or py < 0 or px > w-1 or py > h-1:
		return False

	if c[py][px] == '#':
		return False
	if c[py][px] == 'g':
		return True

	c[py][px] = '#'

	if dfs(px-1,py):
		return True
	if dfs(px,py-1):
		return True
	if dfs(px+1,py):
		return True
	if dfs(px,py+1):
		return True

	return False

h,w = map(int,input().split())

c = []
for i in range(h):
	s = input()
	x = s.find('s')
	if x != -1:
		start = [x,i]
	c.append(list(s))

sx = int(start[0])
sy = int(start[1])

if dfs(sx,sy):
	print('Yes')
else:
	print('No')

そもそもこれが深さ優先探索になっているのか良くわかってません。

他の方はスタックやキューを定義して回答されてましたので、これが良い回答ではないことは確かですね。

##入力例は全て突破したが。。。

AtCoderで回答する際、回答を提出する前に2〜5個ぐらいある入力例をテストコードに突っ込んでちゃんと動作するか確認しますよね。

そこは全て希望通りの出力を得ることができました。

「よっしゃキタ!」

って思ったのですが、回答した結果、以下のようになりました。

スクリーンショット 2019-10-03 20.19.06.png

「めちゃくちゃエラー出てますやん!」

なんでこうなってしまったか悩みまくって夜しか寝れませんでした。

##Pythonでは再帰関数の呼び出し回数に上限がある

結論から先に言うと、こういうことでした。

Pythonでの再帰関数の呼び出し回数の上限は、デフォルトでは1000回だそうです。

上のコードだと完全に1000回を超えてしまいますので、それでエラーが出てたみたいですね。

##解決策

**sys.setrecursionlimit(n)**というものを書いてあげることで、再帰関数の呼び出し上限をn回に設定できます。

ということで完成したコードは次のようになります。

dfs.py
import sys #追加
sys.setrecursionlimit(500*500) #追加

#ここからはさっきと同じ
def dfs(px,py):
	if px < 0 or py < 0 or px > w-1 or py > h-1:
		return False

	if c[py][px] == '#':
		return False
	if c[py][px] == 'g':
		return True

	c[py][px] = '#'

	if dfs(px-1,py):
		return True
	if dfs(px,py-1):
		return True
	if dfs(px+1,py):
		return True
	if dfs(px,py+1):
		return True

	return False

h,w = map(int,input().split())

c = []
for i in range(h):
	s = input()
	x = s.find('s')
	if x != -1:
		start = [x,i]
	c.append(list(s))

sx = int(start[0])
sy = int(start[1])

if dfs(sx,sy):
	print('Yes')
else:
	print('No')

これで無事、ACを取ることができました。

##まとめと余談

競技プログラミングを始めてまだ1ヶ月ぐらいしか経ってないため、こういう細かい部分をよく知っていなかったです。。。
もっと勉強が必要ですね。

そもそももっと良いdfsのコードの書き方があるので、こういうコードを書いた時点でアウトだったのかも・・・。

ちなみに、上のコードをPyPyで実行するとTLEになります。

ざっくりと言うとPyPyは再帰関数と相性が良くないみたいです。

ではまた。

6
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?