狀壓dp練習題首先注意這道題的資料範圍:
\(1\leq n \leq 9\ ,\ 0 \leq k\leq n^2\)是不是真的很小啊,所以我們考慮用狀壓dp或爆搜的辦法解。這道題求方案數,那麼可以很自然的想到用dp或者搜尋,然而對於本題而言,搜尋需要記錄的資訊和狀態太多,會t到天上去,所以只有採用狀壓dp來解決。
注意到n非常小,而且狀態需要記錄的資訊非常多,所以考慮狀態壓縮dp。在這道題裡,當前行的狀態和上一行的狀態有著密切聯絡,而且答案和k有關,所以我們設計狀態f[i][j][k]為前i行已經放了j個國王並且第i行的狀態為k(二進位制)的方案數,那麼\(f[i][j][k] = \sum f[i - 1][j - num[k]][l]\),其中num陣列記錄著一行為狀態k的放的國王的數目,l為上一行符合要求的狀態.
現在的問題就是如何判斷狀態i是否符合要求,這不僅與i本身有關,還和它上一行的狀態j有關,利用左移,右移,&就可以判斷了,它的原理是什麼呢?我們把每個狀態抽象成1個二進位制數,它的第i位表示第i列放不放國王,利用&的性質,可以判斷上下兩行是否衝突,那麼如何判斷當前行是否衝突呢?將i左移1位再與i進行&操作即可。
#include#include#include#include#include#define n 1100
#define m 15
#define ll long long
using namespace std;
int n,k,num[n];
ll f[m][n][n],ans;
bool flag[n];
int main()
f[1][num[i]][i] = 1;
} }for(int i = 2 ; i <= n ; i++)
for(int j = 0 ; j <= k ; j++)
for(int l = 0 ; l < (1for(int last = 0 ; last < (1<>1)&last) continue;
f[i][j][l] += f[i - 1][j - num[l]][last];}}
for(int i = 0 ; i < (1
printf("%lld",ans);
return 0;
}
SCOI2005 互不侵犯
在n n的棋盤裡面放k個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各乙個格仔,共8個格仔。只有一行,包含兩個數n,k 1 n 9,0 k n n 方案數3 2 同sgu223 include include include include ...
SCOI2005 互不侵犯
題目描述 在n n的棋盤裡面放k個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各乙個格仔,共8個格仔。輸入格式 只有一行,包含兩個數n,k 1 n 9,0 k n n 輸出格式 所得的方案數 ly最可愛啦 這題。想了5分鐘,寫了10分鐘,調了...
SCOI2005 互不侵犯
在n n的棋盤裡面放k個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各乙個格仔,共8個格仔。兩個數n,k 1 n 9,0 k n n 方案數。3 2果然啊 狀壓題都是乙個套路 和前面那個noi的題是乙個套路 具體實現也基本一樣 就是記錄的狀態...