[NOI2001] 炮兵陣地

Yorg發表於2024-12-07

演算法

看到資料範圍很小, 考慮狀壓 \(\rm{dp}\)

我們考慮從左上往右下推答案, 那麼顯然的, 我們只需要考慮向上向左方向的衝突情況, 而無需考慮向下向右的

考慮輪廓線 \(\rm{dp}\) , 雖然不太標準就是了

k5qh2z51.png

實際上對於這樣的情況, 我們考慮列舉綠色部分是否選擇, 然後對狀態進行轉移

分類討論

當綠色部分不選擇時

這個時候只要之前的狀態不衝突, 即狀態合法, 都可以轉移

具體的, 對於圖中的這種情況, 我們可以轉移到
g5sgdl19.png

那麼狀態怎麼變化?
具體的, 對於兩行, 都只需要把修改那一位的位置更新, 其他的不變即可

當綠色部分選擇時

這個時候我們需要確保無衝突情況和無障礙物, 我們只需要確保上方兩塊和左側兩塊上沒有炮兵部隊即可

這樣做, 時間複雜度是 \(\mathcal{O} (nm 2 ^ {2m})\) , 顯然是過不去的

考慮到很多狀態根本不合法, 根本跑不滿, 我們提前判斷每種狀態的正確性即可預處理出合法狀態, 這樣可以透過本題

狀態轉移

根據以上的討論, 我們嘗試寫出轉移式子

\(f_{i, j, line_1, line_2}\) 表示考慮 \((i, j)\) , 當前兩行的狀態為 \(line_1, line_2\) 時最多放置的部隊數量

  • 不選擇當前點
    更新 \(line_1\) 的第 \(j\) 位為 \(line_2\) 的第 \(j\) 位, \(line_2\) 的第 \(j\) 位更新為 \(0\)

  • 選擇當前點
    首先判斷地形, 然後判斷 \(line_2\)\(j - 1, j - 2\) 位置, 判斷 \(line_1\)\(j\) 位置和 \(line_2\)\(j\) 位置是否都不為 \(1\) , 轉移

初始化 \(f_{0, 0, 0, 0} = 0\) , 最後的答案即為 \(\max f_{n - 1, m - 1, line_1, line_2}\)

滾動一下即可

實現

框架

  • 對於每一個位置, 列舉產生符合要求的狀態
  • 轉移即可

程式碼

還在調, 後補

總結

狀壓常見最佳化

  • 提前把有效狀態篩出來, 防止無效的轉移

逐一討論的完整性

狀態壓縮這樣的問題, 一定要想辦法簡化程式碼

相關文章