質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.47%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

1083閲覧

競技プログラミング めぐる式二分探索 

teaspoooon

総合スコア1

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2022/08/10 13:41

編集2022/08/11 05:00

前提

使用言語 python

質問内容

pythonで競技プログラミングの勉強をしています.
AOJの二分探索の問題https://onlinejudge.u-aizu.ac.jp/courses/lesson/1/ALDS1/4/ALDS1_4_Bを以下のソースコードを使用して解いたのですが

python

1def i_input(): return int(input()) 2def i_map(): return map(int, input().split()) 3 4 5# listにitemがあったらTrue, なければFalseを返す 6def binary_search(list, item): 7 low = 0 8 high = len(list) - 1 9 while low <= high: 10 mid = (low + high) // 2 11 guess = list[mid] 12 if guess == item: 13 return True 14 elif guess > item: 15 high = mid - 1 16 else: 17 low = mid + 1 18 return False 19 20 21n = i_input() 22s = list(i_map()) 23q = i_input() 24t = list(i_map()) 25 26count = 0 27for i in t: # tの要素がsに含まれているか確認 28 if binary_search(s, i): 29 count += 1 30print(count)

めぐる式二分探索を使って解けずに困っています.(どのように判定式を記述すれば良いか分からない)

python

1def is_ok(mid): 2 """ 3 二分探索中の判定 4 :param mid: 5 """ 6 # ここの条件式をどう書けばよいかわかりません 7 pass 8 9 10def meguru_bisect(ng, ok): 11 12 while (abs(ok - ng) > 1): 13 mid = (ok + ng) // 2 14 if is_ok(mid): 15 ok = mid 16 else: 17 ng = mid 18 return ok 19

全体のソースコード(修正・追加箇所)

python

1# スニペット(再利用可能なソースコード) 2def i_input(): return int(input()) 3 4 5def i_map(): return map(int, input().split()) 6 7 8def is_ok(key): 9 # ここの部分の判定方法がわかりません. 10 11 if s[key] == i: 12 return True 13 else: 14 return False 15 16 17 18def binary_search(ng, ok): 19 while abs(ok - ng) > 1: 20 mid = (ok + ng) // 2 21 if is_ok(mid): 22 ok = mid 23 else: 24 ng = mid 25 return ng 26 27n = i_input() 28s = list(i_map()) 29q = i_input() 30t = i_map() 31 32count = 0 33for i in t: 34 # ngがリストの右端までいくとtの要素(i)を含んでいないと判定 35 if binary_search(-1, n) != n: 36 count += 1 37 38print(count)

実現したいこと

最後に

初めての質問 & Markdown記法なので至らない点があると思いますがよろしくお願いします.

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

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

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

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

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

slemntqe

2022/08/10 14:42

あなたの悩んでいる部分がまさに競技プログラミングの醍醐味なんじゃないでしょうか。どうやってアルゴリズムをコードに落として期待する結果を得るかを考えるのが醍醐味じゃないんですか?それを質問するとは一体どういうことでしょうか。
actorbug

2022/08/10 15:40

meguru_bisect をどのように呼び出して判定するかにより、is_ok の中身の書き方も変わってきます。 meguru_bisect を呼び出す部分のソースも追加してください。
teaspoooon

2022/08/10 17:17

slemntqeさん 返信ありがとうございます。 ご不快な思いをさせて申し訳ございません. おっしゃる通り、分からない部分を悩んでそれを解決できた時の達成感。それが競技プログラミングの醍醐味の一つだと思います. いつもは、質問せず"どうやったらこの問題を解けるのか"を考えて取り組んでおります。(2日以上考えたこともあります) しかし、何日も考えても分からずに結果的に放置してしまうことが増えていました。 そこで、拙い質問の仕方ですが今回質問させていただきました。 ご容赦いただけますと幸いです。
teaspoooon

2022/08/10 17:32

atcorbugさん 返信ありがとうございます。 全体ソースコード def i_input(): return int(input()) def i_map(): return map(int, input().split()) def is_ok(key): # ここの部分の判定方法がわかりません. if s[key] == i: return True else: return False def binary_search(ng, ok): while abs(ok - ng) > 1: mid = (ok + ng) // 2 if is_ok(mid): ok = mid else: ng = mid return ng n = i_input() s = list(i_map()) q = i_input() t = i_map() count = 0 for i in t: # ngがリストの右端までいくとtの要素(i)を含んでいないと判定 if binary_search(-1, n) != n: count += 1 print(count) コードの追加方法など不備がございましたら、ご指摘お願い致しします
actorbug

2022/08/10 20:53 編集

全体ソースコードは、ここに書くのではなく、質問を編集して書き替えてください。 あと、そもそも binary_search の結果の判定方法が間違っているので、is_ok をどのように書いても正しい結果になることはありません。 今回の問題における、めぐる式二分探索の戻り値は、「ソート順を維持する場合に挿入される位置」を表します。 例えば、sが「1, 2, 4, 5」の時、「3」を探すと「2」が返ります。 2番目(数字の4)の位置の直前に「3」を入れると、ソート順が維持されるためです。 つまり、探した数字が戻り値の位置に存在するとは限らないということになります。 めぐる式については、以下のページが詳しいので、読んでみてください。 二分探索アルゴリズムを一般化 〜 めぐる式二分探索法のススメ 〜 https://qiita.com/drken/items/97e37dd6143e33a64c8c
teaspoooon

2022/08/11 05:55

actorbugさん 返信ありがとうございます。 質問を編集し全体のソースコードを追加しました。 また、解説ありがとうございます。actorbugさんの解説の紹介してくださった記事をもとにめぐる式二分探索法について勉強し直してみます。
guest

回答2

0

ベストアンサー

meguru_bisectを「リストsのx番目の要素が今回調べたい値以上となるような最小のインデックス値xを探す関数」として実装してみてはどうでしょう。
(pythonのbisectライブラリに含まれるbisect_leftと同じことをするイメージ)

python

1def i_input(): return int(input()) 2def i_map(): return map(int, input().split()) 3 4def is_ok(mid): 5 return s[mid] >= i # i は for i in t: での i 6 7def meguru_bisect(ng, ok): 8 # リストsの中で s[x] >= i となるような最小のインデックス値xを探す 9 while ok - ng > 1: 10 mid = (ok + ng) // 2 11 if is_ok(mid): 12 ok = mid 13 else: 14 ng = mid 15 return ok 16 17n = i_input() 18s = list(i_map()) 19q = i_input() 20t = list(i_map()) 21 22count = 0 23for i in t: 24 res = meguru_bisect(-1, n) 25 if res != n and s[res] == i: 26 count += 1 27print(count)

投稿2022/08/11 01:58

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

teaspoooon

2022/08/11 05:59

dljfab さん 回答ありがとうございます。 詳しい解説&コメントとても分かりやすかったです。 特に「bisect_leftと同じことをするイメージ」は理解の助けになりました。 回答を元にもう一度、二分探索について勉強します。
guest

0

def i_input(): return int(input()) def i_map(): return map(int, input().split()) def is_ok(index, key): return s[index] >= key def meguru_bisect(key,m): ng = -1 ok = m while (abs(ok - ng) > 1) : mid = (ok + ng) // 2 if is_ok(mid, key): ok = mid else: ng = mid return ok n = i_input() s = list(i_map()) q = i_input() t = list(i_map()) count = 0 for i in t: #一致する数があるか res = meguru_bisect(i, n) if res != n and s[res] == i: count += 1 print(count)

投稿2022/08/11 02:32

編集2022/08/20 03:00
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

退会済みユーザー

退会済みユーザー

2022/08/11 05:06

t[]にs[]の最大値よりも大きな値が含まれる場合、meguru_bisectはnを返すので s[meguru_bisect(i, n)] はIndexErrorになりますよ。
teaspoooon

2022/08/11 17:47

cm67809733さん 回答ありがとうございます。 ご指摘の通り、二分探索についてまだ完全に理解できず、探り探り取り組んでいる状況です。 cm67809733さんの回答を参考にもう一度取り組んでみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問