題目描述
在 \(n \times n\) 的棋盤上放 \(k\) 個國王,國王可攻擊相鄰的 \(8\) 個格仔,求使它們無法互相攻擊的方案總數。
輸入格式
共一行,包含兩個整數 \(n\) 和 \(k\)。
輸出格式
共一行,表示方案總數,若不能夠放置則輸出\(0\)。
資料範圍
\(1 \le n \le 10\),
\(0 \le k \le n^2\)
輸入樣例:
3 2
輸出樣例:16
演算法構造
這道題目,根據資料範圍,不難得出,這道題目考察的是狀態壓縮動態規劃。
分析題目,我們可以得到如下資訊。
乙個點的相鄰八格,不可以有其他點。
棋盤置點型別。
那麼,我們接下來,思考兩個流程。
如何表示狀態
如何轉移方程
表示狀態
顯然,題目給的條件,是國王總數是嚴格限制的,就是k個。
所以說,我們放置了多少個國王,是需要考慮的。
接著,根據棋盤型別的狀態壓縮動態規劃的套路,每一行的狀態,我們需要明白。
也就是每一行,哪些位置放了國王。
綜上所述,我們可以得出,動態規劃的狀態表示。
\[f[i][j][s]為所有只擺在前i行,目前擺了j個國王,而且第i行的擺放狀態為s
\]我們可以舉乙個例子
\[n=5 \\\\
f[1][2][20]表示第一行,已經擺了兩個國王,擺在左邊第乙個,和左邊第三個 \\\\
(20)\_=(10100)\_
\]狀態轉移
在這裡,狀態之間的轉移,必然要滿足,國王之間不會相互攻擊到,那麼我們進行分析。
兩個國王,如果他們存在,直接靠近(上下左右)或者簡介靠近(兩斜對角),那麼顯然是不合法的。
因此,轉換成為狀態理解。
對於乙個狀態集合而言,顯然不能存在相鄰的1.
\[101 (可以) \quad 兩個國王有間隔\\\\
110 (不可以) \quad 國王1和國王2相鄰,可以相互攻擊\\\\
\]因為這會導致,左右兩個國王相鄰,然後發起攻擊。
而且,對於上下兩行而言,不能有共同的一位有1
\[101 \\\\
101\]
因為這會導致,上下兩個國王相鄰,然後發起攻擊。
我們討論完了,上下左右,接下來是最難的兩斜對角。
\[我們設,第i行的狀態為a,第i+1行狀態為b
\]那麼
\[s=a 或 b \\
也就是s=a|b
\]是不可以存在,有相鄰的1的。
\[a=100 \\\\
b=010 \\\\
s=110 \\\\
\]因此這會導致,兩斜對角國王相互攻擊。
綜上所述,我們得到集合轉移的約束條件。
下面是**部分,有很詳細的解說
解題**
#include using namespace std;
const int n=(1<<10)+20;
vectorstate,head[n];
//state放置合法狀態,head[a]表示a對應的放置集合狀態可以轉移到的集合狀態。
int n,k;
long long f[12][110][n];
int cnt[n];
inline bool check(int x)//這裡是檢查有沒有出現相鄰的兩個1
/*這裡是o(1)演算法,來自抽風大佬!!!
inline bool check(int x)//這裡是檢查有沒有出現相鄰的兩個1
*/inline int count(int x)//統計這個狀態有多少個1,也就是放置了多少個國王
inline void pre()
cout<}signed main()
AcWing1064 騎士(狀壓DP)題解
題目傳送門 題目描述 在 n n 的棋盤上放 k 個國王,國王可攻擊相鄰的 8 個格仔,求使它們無法互相攻擊的方案總數。輸入格式 共一行,包含兩個整數 n 和 k。輸出格式 共一行,表示方案總數,若不能夠放置則輸出00。資料範圍1 n 10 0 k n 2 輸入樣例 3 2 輸出樣例 題解 狀態壓縮...
1064 加密字元
1064 加密字元 時間限制 1 sec 記憶體限制 128 mb 提交 25970 解決 12284 狀態 討論版 提交 命題人 admin 題目描述 從鍵盤輸入一批字元,以 結束,按要求加密並輸出。輸入從鍵盤輸入一批字元,佔一行,以 結束。輸出輸出佔一行 加密規則 1 所有字母均轉換為小寫。2 ...
題目1064 反序數
題目描述 設n是乙個四位數,它的9倍恰好是其反序數 例如 1234的反序數是4321 求n的值 輸入 程式無任何輸入資料 輸出 輸出題目要求的四位數,如果結果有多組,則每組結果之間以回車隔開 樣例輸入 樣例輸出 include include int main else if equal true ...