30. 良くない全探索 (1/3)
// i 番目以降の品物で,重さの総和が u 以下となるように選ぶ
// そこまでに選んだ品物の価値の和が vsum
int search(int i, int u, int vsum) {
if (i == n) { // もう品物は残っていない
return vsum;
} else if (u < w[i]) { // この品物は入らない
return search(i + 1, u, vsum);
} else { // 入れない場合と入れる場合を両方試す
int res1 = search(i + 1, u, vsum);
int res2 = search(i + 1, u - w[i], vsum + v[i]);
return max(res1, res2);
}
}
外からは search(0, U, 0) を呼ぶ
31. 良くない全探索 (2/3)
// i 番目以降の品物で,重さの総和が u 以下となるように選ぶ
// そこまでに選んだ品物の価値の和が vsum
int search(int i, int u, int vsum) {
...
}
• 引数が増え,動的計画法に出来ない
– 各 (i, u, vsum) で一度ずつ計算すれば出来るが,効率が悪い
• このような方針で書くと枝刈りができたりするので,不自然な書き方ではないが…
52. ビットマスクの利点
• 状態が 0 から 2n-1 にエンコードされ,そ
のまま配列を利用できる
• 集合の包含関係が数値の大小関係
– 集合 A, B について A ⊂ B ならば
– ビット表現で a ≦ b
53. ビットマスクを用いた全探索
int N, D[30][30]; // 頂点数,距離行列
// 今頂点 v に居て,既に訪れた頂点のビットマスクが b
int tsp(int v, int b) {
if (b == (1 << N) - 1) return D[v][0]; // 全部訪れた
int res = INT_MAX;
for (int w = 0; w < N; w++) {
if (b & (1 << w)) continue; // もう訪れた
res = min(res, D[v][w] + tsp(w, b | (1 << w)));
}
return res;
}
外からは tsp(0, 1) を呼ぶ
54. 動的計画法にする
int tsp(int v, int b) {
...
}
• 配列 memo[MAX_N][1 << MAX_N] 等を作っ
て,tsp(v, b) の結果を記録すれば良い
• ループで記述するのも簡単
– b は降順に回せばよい