配るDPでないと,うまく書けない例?
【類題】
ナップサック問題に雰囲気が似ている:D - Knapsack 1 - 競プロはじめました
DP
考え方
$N$コの弁当からたこ焼き$X$コ・たい焼き$Y$コ(ぴったり)になるよう選ぶ方法の数を$f(N,X,Y)$とする(*1).$0 \leq n \leq N - 1$,$0 \leq x \leq X - 1$,$0 \leq y \leq Y- 1$について$f(n,x,y)$がわかれば,$f(N,X,Y)$が計算できる.よって,$f(N,X,Y)$はDPで求められる.求める答えは\begin{aligned}
\min\{f(N, x, y) \mid x \geq X, y\geq Y \}
\tag{1}
\end{aligned}
となる.\min\{f(N, x, y) \mid x \geq X, y\geq Y \}
\tag{1}
\end{aligned}
ここで,遷移は,$N$コ目の弁当を選ばない場合と選ぶ場合を考えて,
【貰うDP】
\begin{aligned}
f(n,x,y)
=\min\{ f(n - 1, x, y), f(n - 1, x - A_{i}, y - B_{i}) + 1 \}
\end{aligned}
【配るDP】f(n,x,y)
=\min\{ f(n - 1, x, y), f(n - 1, x - A_{i}, y - B_{i}) + 1 \}
\end{aligned}
\begin{aligned}
\begin{cases}
\, f(n + 1, x, y) = \min\{f(n + 1, x, y), f(n, x, y)\} \\
\, f(n + 1, x + A_{i}, y + B_{i})
=\min\{f(n + 1, x + A_{i}, y + B_{i}), f(n, x, y) + 1 \}
\end{cases}
\end{aligned}
である(ただし,$i = 1,2,...,N -1$は可能な範囲をすべて動く).\begin{cases}
\, f(n + 1, x, y) = \min\{f(n + 1, x, y), f(n, x, y)\} \\
\, f(n + 1, x + A_{i}, y + B_{i})
=\min\{f(n + 1, x + A_{i}, y + B_{i}), f(n, x, y) + 1 \}
\end{cases}
\end{aligned}
「配るDP」の場合,$x \geq X$となるものは$x = X$に置き換え,$y \geq Y$となるものは$y = Y$に置き換えれば,式$(1)$を更新操作に統合できる.
以下,$f(n,x,y)$をdp[n][x][y]
で表す.
貰うDP
dp[i][x][y]
に遷移させるように更新する.うまく書けない...
配るDP
dp[i][x][y]
から遷移するように更新する.
INF = 1000 N = int(input()) X, Y = map(int, input().split()) bento = [tuple(map(int, input().split())) for i in range(N)] dp = [[[INF] * (Y + 1) for _ in range(X + 1)] for _ in range(N + 1)] dp[0][0][0] = 0 for i in range(N): A, B = bento[i] for j in range(X + 1): for k in range(Y + 1): dp[i + 1][j][k] = min(dp[i + 1][j][k], dp[i][j][k]) dp[i + 1][min(j + A, X)][min(k + B, Y)] = min(dp[i + 1][min(j + A, X)][min(k + B, Y)], dp[i][j][k] + 1) print(dp[N][X][Y] if dp[N][X][Y] < INF else -1)
*1:「$X$以上・$Y$以上となる最小の個数」と考えても,遷移・初期化含めて全く同じ形になる.