🔙
🔝

【paiza問題集 解説】
Bランク・スキルチェック見本問題セット

長テーブルのうなぎ屋

長テーブルのうなぎ屋

例1) リストを使って解く

リストを使って解く

    n, m = map(int,input().split())
    
    seats = [0] * n
    for _ in range(m):
        a, b = map(int, input().split())
        b -= 1  # 座席番号を 0 番からにする
    
        tmps = [seats[(b+i)%n] for i in range(a)]
        if sum(tmps) == 0:
            for i in range(b, b+a):
                seats[i%n] = 1
    
    print(sum(seats))
    
    

    問題の絵図を見て、26 番の席と 1 番の席をどう繋げるかがポイントになります。座席番号を 0 番から始めるようにすると 0 ~ 25 番となり、

    座る予定の座席 % 26

    と計算すれば、25 番の次の 26番は、イコール 0 番となります。その座席の要素が 0 の時は空席です。
    if sum(tmps) == 0: で全て空席であればという条件文になり、True であれば、その席に1グループ全員座ります。

    ちなみに問題文にある『江戸っ子は気が早いんでぃ。』は、「気が短い」が適切かと思います。😅

例2) セットを使って解く (差集合編)

セットを使って解く (差集合編)

    n, m = map(int,input().split())
    
    seats = set()
    for _ in range(m):
        a, b = map(int, input().split())
        b -= 1  # 座席番号を 0 番からにする
        
        tmp = {i%n for i in range(b, b+a)}
        if seats - tmp == seats:
            seats |= tmp
    
    print(len(seats))
    

    こちらは座席が埋まっている座席番号をセット seats に記録していきます。
    座席番号は 0 ~ n-1 番です。

    まずグループが座席を指定し、そこから人数分指定の座席番号を tmp に書き留めます。

    tmp = {i%n for i in range(b, b+a)}
    

    次に、現在埋まっている座席 seats からこれから座る予定の座席 tmp を差集合演算を使って求めた結果が seats のままなら、座席は空いているということになります。

    if seats - tmp == seats:
        seats |= tmp
    

    seats = {1, 2, 6, 7}
    tmp = {3, 4} の時

    {1, 2, 6, 7} - {3, 4} = {1, 2, 6, 7}

    一致したら、今度は和集合演算で tmpseats に加えます。


    もし埋まっている席が1つでもある場合は結果が seats と一致しません。

    seats = {1, 2, 6, 7}
    tmp = {2, 3} の時

    {1, 2, 6, 7} - {2, 3} = {1, 6, 7}
    2 番の席が埋まっている為


    seats には埋まっている座席番号が入っていますので、その要素数がうな中の総人数になります。

    集合演算については「2章 セットさんは重複を許さない」で学習できます。

例3) セットを使って解く (積集合編)

セットを使って解く (積集合編)

    n, m = map(int,input().split())
    
    seats = set()
    for _ in range(m):
        a, b = map(int, input().split())
        b -= 1  # 座席番号を 0 番からにする
        
        tmp = {i%n for i in range(b, b+a)}
        if not (seats & tmp):
            seats.update(tmp)
    
    print(len(seats))
    

    差集合との相違箇所はここのみです。

    if not (seats & tmp):
    

    seats = {1, 2, 6, 7}
    tmp = {3, 4} の時

    {1, 2, 6, 7} & {3, 4} = set()

    set() は空の集合を表しますので False、それを not すると True になります。

    True なので、tmpseats に加えます。

    seats.update(tmp)
    

    .update() メソッドを使っても seats |= tmp と同じ結果が得られます。.update() メソッドは引数のセットの要素を追加更新する機能なのですが、このメソッドは辞書にも存在します。


    もし埋まっている席が1つでもある場合は結果のセットに重複した座席番号が入っています。

    seats = {1, 2, 6, 7}
    tmp = {2, 3} の時

    {1, 2, 6, 7} & {2, 3} = {2}
    2 番の席が埋まっている

    積集合はそれらしい結果となるのですが、条件式で読み解きにくいですね。特に not のせいで。😓


    seats には埋まっている座席番号が入っていますので、その要素数がうなっ子の総人数になります。

    集合演算については「2章 セットさんは重複を許さない」で学習できます。

例4).rotate() メソッドを使って解く

.rotate() メソッドを使って解く

    from collections import deque
    
    n, m = map(int,input().split())
    
    seats = deque([False] * n)
    for _ in range(m):
        a, b = map(int, input().split())
        b -= 1
    
        seats.rotate(-b)
    
        tmp = [True for i in range(a) if seats[i]]
        if not tmp:
            for i in range(a):
                seats[i] = True
    
        seats.rotate(b)
    
    print(sum(seats))
    

    割った余りとかワケわからなくなって挫折してしまった場合、挫折したままにしておいてはいけないのですが😅、こんなやり方もあります。
    これは単純に双方向キュー deque の機能 .rotate() メソッドを使ってリストを回転し、グループが座る席の最初の座席番号を 0 番目に合わせてから処理する方法です。
    常に 0 番目から始まるようになりますので、リストの要素数を超えてしまうことがありません。

    まず、seats.rotate(-b) で指定した席番号を、要素番号 0 の位置まで引っ張ります。

    a = 2, b = 3 の時
    b -= 1 … b = 2
    【座席番号】 0 1 2 3 4 5

    【座席番号】 2 3 4 5 0 1

    それから tmp でグループが座る予定の席が空いているかをチェックします。空いている場合は要素番号 0 から人数分 1 で埋めます。

    【座席番号】 2 3 4 5 0 1

    終わったら、引っ張った座席を seats.rotate(b) で元の位置に戻しておきます。

    【座席番号】 0 1 2 3 4 5

    右へ左へと振られて客は落ち着いて食事できなさそうですが、江戸っ子はなぜかこういうのには寛容なんです。想像すると滑稽ですね。落語噺が1つ作れそうだ。🤣

例5).rotate() メソッドを使わないで解く

.rotate() メソッドを使わないで解く

    n, m = map(int,input().split())
    
    seats = [False] * n
    for _ in range(m):
        a, b = map(int, input().split())
        b -= 1
    
        seats = seats[b:] + seats[:b]
    
        if not any(seats[:a]):
            seats[:a] = [True] * a
    
        seats = seats[n-b:] + seats[:n-b]
    
    print(sum(seats))
    

    今度は .rotate() メソッドを使わないで同じ様な操作をして同じ様に解きますが、リストなのでスライスが使えて便利ぃ~♪版です。

    まず、seats = seats[b:] + seats[:b] で指定した席番号「より前」と「以降」を前後交換します。

    a = 2, b = 3 の時
    b -= 1 … b = 2
    【座席番号】 0 1 2 3 4 5

    【座席番号】 2 3 4 5 0 1

    先頭から a 人目までの席が空いているかをチェックします。

    if not any(seats[:a]):
    

    if not any([0, 0]):
    

    if not False:
    

    if True:
    

    True の場合、その座席にグループ全員座れます。

    seats = [1, 1, 0, 0, 0, 0]

    終わったら、前後交換した座席を seats = seats[n-b:] + seats[:n-b] で元の位置に戻します。

    【座席番号】 0 1 2 3 4 5
    seats = [0, 0, 1, 1, 0, 0]


    この方法はセットの次に簡単でイメージしやすいかと思います。リストを区切って交換する操作は時々使いますし、こんなやり方もアリでしょう。