[AOJ] No. 0363 積み荷の配置
問題
方針
\( i \) 列目に荷物が置けるかどうかは \( i – 1 \) 列目と \( i \) 列目を調べれば良いので、動的計画法を行います。各列の状態は荷物か置けるマスがあるかどうかの \( 2 \) 通りであり \( 4 \)マスあるので、全体で \( 16 \) 通りあります。なので、bitDP を行います。
更新式
\( d(i, j) \) を \( i \) 列目のマスが \( j \) であるときの置くことができる荷物の最大数とします。ここで、\( j \) は \( 2 \) 進数で表現されたマスの状態とします。\( i \) 列目のマスの状態を \( b_i\) とすると、初期値は \( d(0, b_0) = 0\) とし、それ以外は、\( d(i, j) = -1 \) とします。
荷物の置き方は、\( 1100, 0110, 0011, 1111\) の \( 4 \) 通りあり、荷物を置かないパターンは \( 0000 \) と表します。
\( d(i – 1, j) \neq -1\) のとき、遷移できる状態を考えます。ここで、\( c_1 = 1100 \) とします。 \( i -1, \ i\) 列目に、\( c_1 \) の置き方ができるとき、\( j \wedge c_1 = 0 \) ならば、\( d(i, b_i \vee c_1) \leftarrow d(i -1, j) + 1 \) と更新することができます。
コード
#include <bits/stdc++.h> using namespace std; typedef long long ll; int c[50000][4]{}; bool check(int i, int j) { for (int k = 0; k < 4; k++) { int t = 1<<k; if ((t & j) != 0 && c[i][k] == 1) return false; } return true; } int main() { int H, N; cin >> H >> N; int x[N], y[N]; for (int i = 0; i < N; i++) { cin >> x[i] >> y[i]; c[y[i]][x[i]] = 1; } int d[H][16]{}; fill(d[0], d[H], -1); int a = 0; for (int i = 0; i < 4; i++) { if (c[0][i] == 1) a += (1<<i); } d[0][a] = 0; // 0000 1100 0110 0011 1111 // 0 3 6 12 15 for (int i = 1; i < H; i++) { int t = 0; // i-1 列目の配置 int u = 0; // i列目の配置 for (int j = 0; j < 4; j++) { if (c[i - 1][j] == 1) t += (1<<j); if (c[i][j] == 1) u += (1<<j); } // 何も置かない for (int j = 0; j < 16; j++) { d[i][u] = max(d[i][u], d[i - 1][j]); } for (int j = 0; j < 16; j++) { if (d[i - 1][j] < 0) continue; for (int k = 0; k < 3; k++) { int c = (1<<k) + (1<<(k + 1)); if (check(i - 1, c) && check(i, c) && (j & c) == 0) { d[i][u | c] = max(d[i][u | c], d[i - 1][j] + 1); } } if (check(i, 15) && check(i - 1, 15) && (j & 15) == 0) { d[i][15] = max(d[i][15], d[i - 1][j] + 2); } } } int v = 0; for (int i = 0; i < 16; i++) { v = max(v, d[H - 1][i]); } cout << v << "\n"; return 0; }
ディスカッション
コメント一覧
まだ、コメントがありません