Kalıp #34
Bitmask DP
UzmanBitmask durumlu DP: TSP tarzı, atama, alt küme geçişleri.
Ne zaman kullanılır
Durum kullanılan/ziyaret edilen öğeleri takip etmeli ve n küçükse (≤ 20). Maskedeki her bit dahil edilme. TSP, atama, alt küme seçiminde yaygın.
Tanıma ipuçları
- Küçük n (≤ 20) alt küme durumlu
- TSP / en kısa Hamilton yolu
- Kısıtlarla öğeleri gruplara ata
- Durum = kullanılan öğelerin bitmaski
Yaygın tuzaklar
- 2^n durum n=20 sonrası patlar
- Memoizasyon unutmak (DP olmadan eksponansiyel)
- Mask geçiş yönü (bit ekle vs çıkar)
90 saniyelik tanıma egzersizi
Hangisi en iyi uyuyor?
- Küçük n (≤ 20) alt küme durumlu
- TSP / en kısa Hamilton yolu
- Kısıtlarla öğeleri gruplara ata
Etkileşimli
Zihinsel model
Değişmezin tam adım adım anlatımı. Duraklat, noktalara tıkla veya ← → kullan. Her adımı kendi cümlelerinle anlatmayı hedefle.
maske biti i = şehir i ziyaret edildi
n ≤ 20 ve durum “hangi öğeler kullanıldı”: bitmask. 3 şehir, TSP-tarzı.
Nasıl düşünülür
Bitmask DP, durumun geçerli kümede hangi öğelerin olduğunu hatırlaması gereken problemler içindir. n bitlik bir mask üyeliği kodlar: i biti setse i öğesi kullanımda. DP geçişleri bir biti çevirerek bir öğe ekler/çıkarır. Ana kısıt: n ≤ ~20 olmalı çünkü durum uzayı 2^n’dir, n=20’de bir milyon durum, uygulanabilir; n=25’te 33 milyon, sınırda.
Kanonik problem TSP (gezgin satıcı): dp[mask][last], mask içindeki düğümleri ziyaret edip last’ta biten minimum maliyettir. Geçiş: ziyaret edilmemiş her j için dp[mask | (1<<j)][j] = min(dp[mask][last] + dist[last][j]). Temel: dp[1<<start][start] = 0. Cevap: kapalı tur için min(dp[(1<<n)-1][last] + dist[last][start]), açık için min(dp[full][last]).
Şablon şekilleri
| Şekil | Temel hamle | Örnek |
|---|---|---|
| TSP | dp[mask][last]; ziyaret edilmemiş j ekle |
LC 943 |
| Atama / partisyon | dp[mask]; bir gruba öğe dene |
LC 1655, LC 1799 |
| Maliyetli alt küme seçimi | dp[mask]; kalanlar alt kümesinde geçiş |
LC 1994 |
| Renklendirme / kısıt | dp[mask][renk]; geçerli uzantılar |
LC 1931 |
Karmaşıklık temeli
O(2^n * n) zaman, O(2^n * n) alan (veya last katlanırsa O(2^n)). n=20’de ~4 * 10^7 işlem, süreye sığar. n > 22’de problemin daha hızlı bir yapı kabul edip etmediğini düşün.
Şablondan probleme
- n’nin ≤ ~20 olduğunu doğrula; daha büyükse farklı teknik ara (greedy, flow, meet-in-the-middle).
- Maskı tanımla: hangi öğeler “kullanıldı” veya “ziyaret edildi”.
- DP hücresini tanımla:
dp[mask]veyadp[mask][ekstra](son düğüm, sayı, grup). - Maskları küçükten büyüğe iterasyona et; her birinde kullanılabilir her öğeyi dene.
- Cevabı tam masktan veya son boyut üzerinden min’den çıkar.
Şablon
TypeScript, Python ve C#’te aynı iskelet. Değişmezi uyarla; yapıyı koru.
/** Bitmask DP template: TSP (open path) over a distance matrix. */
export function tspOpen(dist: number[][]): number {
const n = dist.length;
const full = (1 << n) - 1;
const dp: number[][] = Array.from({ length: 1 << n }, () =>
new Array<number>(n).fill(Infinity),
);
for (let i = 0; i < n; i++) dp[1 << i]![i] = 0;
for (let mask = 1; mask <= full; mask++) {
for (let last = 0; last < n; last++) {
if (!(mask & (1 << last))) continue;
const cur = dp[mask]![last]!;
if (cur === Infinity) continue;
for (let j = 0; j < n; j++) {
if (mask & (1 << j)) continue;
const next = mask | (1 << j);
dp[next]![j] = Math.min(dp[next]![j]!, cur + dist[last]![j]!);
}
}
}
let ans = Infinity;
for (let last = 0; last < n; last++) ans = Math.min(ans, dp[full]![last]!);
return ans;
}/** Bitmask DP template: TSP (open path) over a distance matrix. */
export function tspOpen(dist: number[][]): number {
const n = dist.length;
const full = (1 << n) - 1;
const dp: number[][] = Array.from({ length: 1 << n }, () =>
new Array<number>(n).fill(Infinity),
);
for (let i = 0; i < n; i++) dp[1 << i]![i] = 0;
for (let mask = 1; mask <= full; mask++) {
for (let last = 0; last < n; last++) {
if (!(mask & (1 << last))) continue;
const cur = dp[mask]![last]!;
if (cur === Infinity) continue;
for (let j = 0; j < n; j++) {
if (mask & (1 << j)) continue;
const next = mask | (1 << j);
dp[next]![j] = Math.min(dp[next]![j]!, cur + dist[last]![j]!);
}
}
}
let ans = Infinity;
for (let last = 0; last < n; last++) ans = Math.min(ans, dp[full]![last]!);
return ans;
}- 1#943 Find the Shortest SuperstringRehberhard
- 2#1655 Distribute Repeating IntegersRehberhard
- 3#1799 Maximize Score After N OperationsRehberhard
- 4#1931 Painting a Grid With Three Different ColorsRehberhard
- 5#1994 The Number of Good SubsetsRehberhard
- 6#2003 Smallest Missing Genetic Value in Each SubtreeRehberhard