首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

BZOJ 1801 中國象棋:狀態壓縮 DP 計算放炮方案數

     編輯:關於C++

題目大意

在 N×M 棋盤放置若干炮(可 0 個),任意兩炮不能互相攻擊。中國象棋炮的走法:同行/同列無阻隔時可攻擊。求方案數模 9999973。

關鍵觀察

炮不互相攻擊 ⇔ 每行每列炮數 ≤ 2,且若某行/列有 2 炮,中間必有至少一個棋子阻隔。但題目無其他棋子,故實際限制為:每行每列最多 1 炮?

細讀題意:炮攻擊需中間有棋子作「炮架」。無其他棋子時,同行/同列任意兩炮無阻隔 ⇒ 可攻擊。因此每行每列至多 1 炮。但樣例 1 3 輸出 7(2³-1=7),說明允許同行多炮?

重新理解:題目說「沒有任何一個炮可以攻擊另一個炮」。若同行放 2 炮,中間無子 ⇒ 可攻擊,非法。但若同行放 2 炮且中間有其他炮?炮本身可作炮架!

正確模型:每行每列炮數 ≤ 2。若某行有 2 炮,它們之間無其他炮 ⇒ 可攻擊(非法);若有 3 炮,中間的炮可作炮架保護兩側?但題目說「任意兩炮不能攻擊」,三炮情況下首尾仍可通過中間炮攻擊 ⇒ 非法。故每行每列 ≤ 2 炮,且若有 2 炮則它們之間不能有空位?實際上標準解法為:每行每列 ≤ 2 炮,且全盤滿足此條件即可(炮之間可互為炮架)。

DP 狀態定義

按行處理。狀態 f[i][j][k]:前 i 行,有 j 列放了 1 個炮,k 列放了 2 個炮的方案數。

第 i 行放置選擇(6 種):

  1. 不放
  2. 放 1 炮於 0 炮列
  3. 放 1 炮於 1 炮列
  4. 放 2 炮於兩個 0 炮列
  5. 放 2 炮於兩個 1 炮列
  6. 放 2 炮於一個 0 炮列和一個 1 炮列

轉移方程

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved