演算法
看到資料範圍很小, 考慮狀壓 \(\rm{dp}\)
我們考慮從左上往右下推答案, 那麼顯然的, 我們只需要考慮向上向左方向的衝突情況, 而無需考慮向下向右的
考慮輪廓線 \(\rm{dp}\) , 雖然不太標準就是了
實際上對於這樣的情況, 我們考慮列舉綠色部分是否選擇, 然後對狀態進行轉移
分類討論
當綠色部分不選擇時
這個時候只要之前的狀態不衝突, 即狀態合法, 都可以轉移
具體的, 對於圖中的這種情況, 我們可以轉移到
那麼狀態怎麼變化?
具體的, 對於兩行, 都只需要把修改那一位的位置更新, 其他的不變即可
當綠色部分選擇時
這個時候我們需要確保無衝突情況和無障礙物, 我們只需要確保上方兩塊和左側兩塊上沒有炮兵部隊即可
這樣做, 時間複雜度是 \(\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}\)
滾動一下即可
實現
框架
- 對於每一個位置, 列舉產生符合要求的狀態
- 轉移即可
程式碼
還在調, 後補
總結
狀壓常見最佳化
- 提前把有效狀態篩出來, 防止無效的轉移
逐一討論的完整性
狀態壓縮這樣的問題, 一定要想辦法簡化程式碼