アルゴリズム学習2)3月3日


Intro

  • 3月第2週は諸般の事情により行えませんでした….(言い訳)
  • 今週は非常に簡単な問題から回避型DP問題を解いた.
  • 2839号送糖


    https://www.acmicpc.net/problem/2839

    解法

  • どのように儀式を決めるべきか分からないので、盲目的に3から18まで手でルールを模索します.
  • kg時の糖袋数
  • (i-3)kg時の糖袋数+1
  • (i-5)kg時の糖袋数+1
  • には2つのケースがあります.袋の最低個数を出力しなければならないので、2つの値のうち、小さい値がikgの場合、糖袋の個数として決定する.
  • は、最初にdpの値を袋の予想最大個数より大きく設定し、この値を超えると正確な個数が得られないため、−1を出力する必要がある.
  • 正しいコード

    N = int(input())
    
    d = [5001] * (N+3)
    d[3] = 1
    d[5] = 1
    
    for i in range(6, N+1) :
        d[i] = min(d[i-3]+1, d[i-5]+1)
    
    if d[N] >= 5001:
        print(-1)
    else:
        print(d[N])

    作成1463号1


    https://www.acmicpc.net/problem/1463

    解法

  • という問題も頭に入らず、1から18まで手書きで書かれています.
  • 手書きなので、数字で3回に分けた場合、1回か2回か3回の場合、1~3回の場合があります.
  • の小さい値からdp値を求め、大きな数で利用できるようにします.
  • ex)Xが18の場合:dp[6]、dp[9]、dp[17]の最小値+1はdp[18]の値である.
  • 3号はすべての数字で、まずdp[i-1]+1をdp[i]値に設定し、dp[i/3]+1を2(dp[i/2]+1)に分けてそれぞれdp[i/2]+1と比較し、最大値を求めた.
  • 正しいコード

    N = int(input())
    
    d = [0] * (N+1)
    
    for i in range(2, N+1):
    
        d[i] = d[i-1] + 1
    
        if i % 3 == 0:
            d[i] = min(d[i], d[i//3] + 1)
        if i % 2 == 0 :
            d[i] = min(d[i], d[i//2] + 1)
            
    
    print(d[N])

    2579番の階段を上る


    https://www.acmicpc.net/problem/2579

    解法

  • はあまり理解できず、他の草を参考にしました.
  • i iの1段目であれば、2つの値のうち大きい値がdp[i]と決定される2つのケースがある.
  • i-最初の階段から上がった
  • i-2番目の階段から上がった
  • i-1階段を上ると、前の階段はi-3です.
  • dp[i]=score[i]+score[i-1]+dp[i-3].
  • (次のコードでは、scoreの最初のステップはscore[0]なので、もう1つ減算します.)
  • i-2番目の階段を上がります
  • dp[i]=score[i]+dp[i-2].
  • 正しいコード

    n = int(input())
    
    score = []
    for i in range(n):
        score.append(int(input()))
    
    if n == 1:
        print(score[0])
    else:
        dp = [0]*(n+1)
        dp[1] = score[0]
        dp[2] = score[0] + score[1]
    
        for i in range(3, n+1):
            dp[i] = max(score[i-1]+score[i-2]+dp[i-3], score[i-1]+dp[i-2])
    
        print(dp[n])

    1912回連続


    https://www.acmicpc.net/problem/1912

    解法

  • 簡単に言えば、i回目のときはi値のみをとり、i-1の最低値にiを加えた値のうち、より大きな値をdp[i]値とし、最大のdp値を求めればよい.
  • 正しいコード

    n = int(input())
    num = list(map(int, input().split()))
    
    dp = [0] * n
    dp[0] = num[0]
    
    for i in range(1, n):
        dp[i] = max(dp[i-1]+num[i], num[i])
    
    print(max(dp))

    11726号2 xnタイル


    https://www.acmicpc.net/problem/11726

    解法

  • 実際、この問題は以前は解答したことがあるが、次の問題と比較するために書いた.
  • n回目の充填方法は、n−2回に2つの1 x 2タイルを配置する方法と、n−1回に1つの2 x 1タイルを配置する方法の合計に等しい.
  • 従って、タイルの数はtiles[n]=tiles[n−1]+tiles[n−2]である.

    正しいコード

    n = int(input())
    tiles = [0]*1001
    tiles[1] = 1
    tiles[2] = 2
    
    for i in range(3, n+1):
        tiles[i] = tiles[i-1]+tiles[i-2]
    
    print(tiles[n]%10007)

    11727号2 xnタイル2


    https://www.acmicpc.net/problem/11727

    解法


  • 上の問題と似ていますが、2 x 2タイルが追加されました.上記の問題の解法と同様であるが,2 x 2を添加し,n−2法では2つの1 x 2タイルを置く代わりに2 x 2を添加した.
  • 従って、タイルの数はd[n]=2*d[n−2]+d[n−1]である.

    正しいコード

    n = int(input())
    
    d = [0] * (n+1)
    
    if n == 1:
        d[1] = 1
        print(d[1]%10007)
    else:
        d[1] = 1
        d[2] = 3
    
        if n == 2:
            print(d[2]%10007)
        else:
            for i in range(3, n+1):
                d[i] = 2*d[i-2] + d[i-1]
    
            print(d[n]%10007)

    1890号ジャンプ台


    https://www.acmicpc.net/problem/1890

    解法

  • の第1列のdp値を1に設定します.
  • の最初のセルからすべてのセルを繰り返しチェックし、そのセルの数字に従ってそれぞれ右側と下に移動すると、移動可能なセルのdp値に現在のセルのdp値が加算されます.
  • はすべてのセルを迂回し、最後のセル(i=N−1,j=N−1)に到達した後、繰り返し文から逃れ、dp[N−1][N−1]を出力する.
  • 正しいコード

    N = int(input())
    map = [list(map(int, input().split())) for i in range(N)]
    
    dp = [[0] * N for i in range(N)]
    dp[0][0] = 1
    
    for i in range(N):
        for j in range(N):
            if i==N-1 and j==N-1:
                break
    
            right = j + map[i][j]
            bottom = i + map[i][j]
    
            if right < N:
                dp[i][right] += dp[i][j]
            if bottom < N:
                dp[bottom][j] += dp[i][j]
    
    print(dp[N-1][N-1])