🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Q&A

1回答

1360閲覧

paizaの陣取りゲームでタイムオーバーになってしまう

E28

総合スコア12

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

0グッド

0クリップ

投稿2020/12/11 02:15

編集2020/12/11 02:17

前提・実現したいこと

処理する入力数の多い問題でタイムアウトになってしまうので、これを回避したい。
newすると時間がかかると聞いたことがあるが、該当コードではどこに時間がかかっているかわからない。
該当の問題はこちら(paiza レベルアップ問題集 陣取りゲーム

発生している問題・エラーメッセージ

テスト3以降の与られるマス目が1000*1000のものでタイムオーバーと表示されてしまう。

該当のソースコード

ruby

1A = "A" 2B = "B" 3# 盤面 4map = Array.new 5# A, Bのターン数と広げた陣地を登録するキュー 6a_id = 0 7b_id = 0 8check_map_A = Array.new 9check_map_B = Array.new 10 11# 入力される値 12# H W ・ 1 行目では、マップの行数 H , 列数 W が与えられます。 13# N ・ 2 行目では、先攻のプレイヤーの名前 N が与えられます。 14# S_0 ・ 続く H 行のうち i 行目 (0 ≦ i < H) には、盤面の i 行目の文字をまとめた文字列 S_i が与えられ、 15# ... S_i の j 文字目は、盤面の i 行目の j 列目に書かれている文字を表します。(0 ≦ j < W) 16# S_(H-1) 17 18# 与られる情報を取得 19h, w = gets.chomp.split(" ").map(&:to_i) 20turn = gets.chomp 21h.times do 22 map << gets.chomp.split("") 23end 24 25# A, Bのスタート地点を取得する 26def check_start(map, turn) 27 map.each_with_index do |row, row_i| 28 row.each_with_index do |box, col_i| 29 return {id: 0, row: row_i, col: col_i} if box == turn 30 end 31 end 32end 33 34# 1手前に登録した座標を元に上下左右に陣地を広げる 35def check_around (check_map, map, id, turn) 36 # キュー(check_map)から1手前の座標を一つ取り出し、空いている上下左右のマスの座標を新たにキューに登録 37 # 1手前に登録した座標がなくなるまで繰り返す 38 while check_map.first[:id] == id 39 box = check_map.first 40 id = box[:id] 41 row_i = box[:row] 42 col_i = box[:col] 43 check_map << {id: id + 1, row: row_i - 1, col: col_i} if map.dig(row_i - 1, col_i) == "." && row_i - 1 >= 0 44 check_map << {id: id + 1, row: row_i + 1, col: col_i} if map.dig(row_i + 1, col_i) == "." 45 check_map << {id: id + 1, row: row_i, col: col_i - 1} if map.dig(row_i, col_i - 1) == "." && col_i - 1 >= 0 46 check_map << {id: id + 1, row: row_i, col: col_i + 1} if map.dig(row_i, col_i + 1) == "." 47 check_map.shift 48 return if check_map.empty? 49 end 50 # 新たに登録した座標にA, Bを記入する 51 check_map.each do |box| 52 map[box[:row]][box[:col]] = turn 53 end 54end 55 56# A,Bの陣地の数を数える 57def count_box(map, turn) 58 count = 0 59 map.each do |row| 60 row.each do |box| 61 if box == turn 62 count += 1 63 end 64 end 65 end 66 return count 67end 68 69# A, Bのスタート地点を各キューに登録する 70check_map_A << check_start(map, A) 71check_map_B << check_start(map, B) 72 73# A, Bのキューがなくなる=新たに陣地が広げられなくなるまで繰り返す 74while !check_map_A.empty? || !check_map_B.empty? do 75 # 各手番の陣地を広げる 76 if turn == A 77 check_around(check_map_A, map, a_id, A) if !check_map_A.empty? 78 a_id += 1 79 else 80 check_around(check_map_B, map, b_id, B) if !check_map_B.empty? 81 b_id += 1 82 end 83 # 手番を入れ替える 84 turn = (turn == A)? B : A 85end 86 87# A, Bの陣地数と多い方を出力する 88a = count_box(map, A) 89b = count_box(map, B) 90puts "#{a} #{b}" 91puts a > b ? "A" : "B"

試したこと

ローカルで実行してみたところ、1010マスでは問題なく動くが、10001000マスになると手番40回目あたりから動作に時間がかかってしまう。

補足情報(FW/ツールのバージョンなど)

使用言語:Ruby

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

どこに時間がかかっているかわからない。

とのことなので、まずはbenchmarkライブラリーを使って計測した方が良いかと思います。

Ruby

1require 'benchmark' 2 3Benchmark.bm 10 do |r| 4 r.report "処理1" do 5 # (計測したい処理その1) 6 end 7 r.report "処理2" do 8 # (計測したい処理その2) 9 end 10end

user system total real 処理1 1.217000 0.000000 1.217000 ( 1.210070) 処理2 0.858000 0.000000 0.858000 ( 0.856049)

参考:https://qiita.com/scivola/items/c5b2aeaf7d67a9ef310a

投稿2020/12/11 04:56

no1knows

総合スコア3365

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問