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

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

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

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

4回答

2040閲覧

Python3 等差数列 項数が不明の場合

python3_beginer

総合スコア46

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2018/05/06 07:27

編集2018/05/06 14:55

問題)

二つの風呂 A,B に、特別なルールで水を貯めていくゲーム

Aの風呂には、あらかじめ、s リットルの水が含まれている。

A,B それぞれの風呂の容量は, a,b である。

入力値

s, a, b

条件
すべてのテストケースにおいて、以下の条件をみたします。

・1 ≦ S ≦ 1,000,000
・1 ≦ a, b ≦ 1,000,000
・a ≧ S + 10  ・すなわち、 風呂A には必ず 1 回以上水を行われる。

以下のルールに従って、水を貯めていく。

あらかじめ、s リットル入っているAの風呂に、10リットル の水をためる

次に、Bに (s + 10) リットルの 水を貯める

そして、A、B 交互に 1,010 リットル ずつの水を交互に入れる

水を入れ続け、溢れた方が負けである。

出力値には、勝った方の、すなわち溢れなかった方の風呂の名前と、

相手が溢れた直前に入れた、勝者の水の量を求めたい。

入力例1
1 1500 2050
出力例1
B 2021

入力例2
10 50 1019
出力例2
A 20

コード 入力例1 1 1500 2050 出力例1 B 2021 上記の入力値の場合、A,Bの風呂に入れる水の量は以下のような等差数列になる Aの第1項、2項を除き、1010ずる増える A: 1 11 1021 2031 3041 4051 5061 B: 1011 2021 3031 4041 5051 6061 入力例2 10 50 1019 出力例2 A 20 A: 10 20 1030 2040 3050 4060 B: 1020 2030 3040 4050 5060 s,a,b = map(int, input().split()) print(s,a,b) #等差数列の項数が不明だが、n= 10 と仮定 l_1 = s+10 l_2 = s+1010 m = 1010 n = 10 #A,B の等差数列 lst_a = list(range(l_1, l_1+m*n, m)) lst_a.insert(0,s) lst_b = list(range(l_2, l_2+m*n, m))

#質問

今回の問題だと、等差数列の項数が不明のため式を作成できない

更に、ひとつの風呂の限界値は求められるが、ふたつ交互に入れていく場合の式が作れない

アドバイス等頂けたら嬉しいです。

#試したこと

コード s,a,b = map(int, input().split()) print(s,a,b) #等差数列の項数が不明だが、n= 10 と仮定 l_1 = s+10 l_2 = s+1010 m = 1010 n = 10 #A,B の等差数列 lst_a = list(range(l_1, l_1+m*n, m)) lst_a.insert(0,s) lst_b = list(range(l_2, l_2+m*n, m)) #1つの風呂の溢れる前の、入れた水の量を出力 for x in range(n): if lst_a[x] > a: break print(lst_a[x-1])

#追記質問

配列ではなく、while構文を利用するようにとアドバイスをいただきました。

A、B それぞれにwhile構文を使い、それぞれの浴槽の水が溢れる直前に入れた水の量を表示できた。

しかし、ルール上にあるように交互に入れた際の、勝った相手のみ表示させたい。

二つの条件を合わせたwhile文が書けません。

アドバイス等頂きたいです。

#追記条件

加えて、入力値の条件を追記しました。

入力値

s, a, b

条件
すべてのテストケースにおいて、以下の条件をみたします。

・1 ≦ S ≦ 1,000,000
・1 ≦ a, b ≦ 1,000,000
・a ≧ S + 10  ・すなわち、 風呂A には必ず 1 回以上水を行われる。

コード s,a,b = map(int, input().split()) print(s,a,b) #Aの一回目 water_a = s+10 #Bの一回目 water_b = s+1010 #Bの一回目が限界値を越えていたら、Aの勝利 if water_b > b: print("A" + " " + water_a) #上記以降は交互に入れる else: while water_a < a: water_a += 1010 print(water_a) break #Bの一回目はクリアしたため、順次 1010リットルずつ足していく while water_b < b: water_b += 1010 print(water_b) break #出力値 1021 2021

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

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

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

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

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

fuzzball

2018/05/07 05:41 編集

ルールでは最初に「Bに (s + 10) リットルの 水を貯める 」と書いてあるのに、コードではBの初期値が s+1010 になってる。どっちが正しいのか?
guest

回答4

0

風呂にたまる水の量が等差数列となることに気が付いているのであれば、数学的アプローチで答えを出すという方法もあります。
考え方として、水があふれるギリギリの項数を以下によって定式化します。

風呂の容量 < 2回目の水量 + 1010 × (n-1)

つまり上記を満たす最小のnを風呂aと風呂bに対して計算して結果の大きいほうが勝者であり、敗者のnで計算される勝者の水量が直前の水量ということになります。
解析的に答えを出すのであれば、

風呂の容量 = 2回目の水量 + 1010 × (n-1)

と置き換えた上で、n=…の形式に置き換えたものをコードにすればいいことになります。(答えが少数部を含む場合は切り上げが必要であり、整数の場合は1を加算する必要があります)

答えを出す計算式を手計算で出すことが面倒であれば、scipy.optimizerの中に便利な関数があるのでそちらを使うという方法もあります。上記の定式化であれば、minimize_scalarがいいかと思います。
まず、答えを出したい式を関数として定義し直します。

func(n) = np.abs(2回目の水量 + 1010 × (n-1) - 風呂の容量)

np.absはminimize_scalarを適用するため、答えではない場合は常に正数となるように補正するためのものです。
あとは、minimize_scalar(func)とすると、最小値(今回の場合は0)となるnを出力するので、これをもとに勝者判定とその時の水量を計算すればいいことになります。

少しマニアックな方法なので参考程度として見てください。

投稿2018/05/06 19:07

R.Shigemori

総合スコア3376

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

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

python3_beginer

2018/05/07 03:21

コメントありがとうございます。 斬新な数学的アプローチを知れてとても参考になりました。 初心者のため、初見ですべて理解するのは難しいですが、時間をかけて吸収したいと思います。 ご指導ありがとうございました。
guest

0

出力値には、勝った方の、すなわち溢れなかった方の風呂の名前と、
相手が溢れた直前に入れた、勝者の水の量を求めたい。

プレイヤーAの第2ターンだけなんか特殊ですが、基本的にプレイヤーA、B両方について「さっき入れた水の量」と「風呂の残り容量」だけを変数に保持した上でwhile文を回せば十分です。
つまり配列を使う必要はありません。

算数的な考察を行えばもっと高速な解き方が得られそうな気もします。


追記: 表題の件、appendを使えばあとから要素数を増やせます(上記の理由でオススメしません)。

python

1>>> foo = list() 2>>> foo.append(10) 3>>> foo.append(10) 4>>> foo.append(10) 5>>> foo.append(10) 6>>> foo.append(10) 7>>> foo 8[10, 10, 10, 10, 10]

投稿2018/05/06 07:43

編集2018/05/06 07:46
set0gut1

総合スコア2413

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

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

python3_beginer

2018/05/06 14:57

コメントありがとうございます。 アドバイスを活かして、while を利用しましたが、新たに疑問点にぶつかりました。 大変恐縮ですが、追記質問致しました。 アドバイス頂けたら幸いです。
set0gut1

2018/05/06 15:36

while True などとしてループを作り、同一ループ中で「A注水」→「A敗北判定」→「B注水」→「B敗北判定」とすることで、交互に水を入れる実装ができそうです。
python3_beginer

2018/05/07 03:26

ありがとうございます。 同一ループの中に組み込んで再編集してみます。
guest

0

bの初期値がs+1010の場合の回答です。

python

1nowa = s + 10 2#ここでAが溢れることはないのでチェック不要 3nowb = s 4while nowa <= a: 5 nowb += 1010 6 if nowb > b: 7 break 8 nowa += 1010 9 10if nowa <= a: 11 #Aの勝ち 12 print("A", nowa) 13else: 14 #Bの勝ち 15 print("B", nowb)

投稿2018/05/07 05:49

編集2018/05/07 06:44
fuzzball

総合スコア16731

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

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

0

ベストアンサー

何回読んでもルールがよくわからなかったので(どこが双方の第一ターンなのかわからない)、とりあえず適当に書いたのを。

python

1s, a_max, b_max = map(int, input().split()) 2 3# initialize 4a_water = s 5b_water = 0 6 7flag = True 8# 1st turn 9a_water += 10 10if a_water > a_max and flag: 11 winner = "B" 12 last_water = b_water 13 flag = False 14 15b_water += s + 10 16if b_water > b_max and and flag: 17 winner = "A" 18 last_water = a_water 19 flag = False 20 21if flag: 22 # 2nd or later 23 while True: 24 a_water += 1010 25 if a_water > a_max: 26 winner = "B" 27 last_water = b_water 28 break 29 30 b_water += 1010 31 if b_water > b_max: 32 winner = "A" 33 last_water = a_water 34 break 35print(winner, last_water)

修正点について

最初のコードはこういう挙動になっておりました。

text

11 5 5 # 入力 2B 11 # 出力

こっちの方が望ましいと思うので直しました。

text

11 5 5 2B 0

投稿2018/05/06 15:39

編集2018/05/07 05:16
hayataka2049

総合スコア30933

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

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

python3_beginer

2018/05/07 03:26

コメントありがとうございます。 こちらのコードで出力値を求めることができました。ベストアンサーに選ばさせて頂きました。 while文と変数の定義が上手くできず、答えまで至らなかったです。 hayataka2049さんのコードを参考に勉強します。 ご指導ありがとうございました。
hayataka2049

2018/05/07 05:16 編集

すみません、1回目でどっちも溢れたときの判定が適当すぎました。修正版を上げたので、そっちも見てください
fuzzball

2018/05/07 06:10

「1回目でどっちも溢れたとき」はありえません。 というか、どちらかが溢れた時点で終了なので「どっちも溢れたとき」がありえません。
hayataka2049

2018/05/07 06:16

元のコードで先に両方加算してから判定するという手抜きをしていたので、それの修正をしたという意味です。
fuzzball

2018/05/07 06:36 編集

「1回目でどっちも溢れたとき」はありえないので修正する意味は無いです。 2行目に関しては取り消します。 ちなみに 1 5 5 は入力条件に合っていないので検証する必要がありません。
hayataka2049

2018/05/07 06:40

私のルールの理解が足りなかったのですが、今理解しました。 a ≧ S + 10  ・すなわち、 風呂A には必ず 1 回以上水を行われる。 があるから、aは一回目の+10では溢れないということですね。了解です。ご指摘ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問