在n×n的棋盤裡面放k個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上
左下右上右下八個方向上附近的各乙個格仔,共8個格仔。
只有一行,包含兩個數n,k ( 1 <=n <=9, 0 <= k <= n * n)
方案數。
3 2題目鏈結(bzoj)
資料(loj)
首先看到資料範圍第一反應這題不是用搜尋就是狀壓dp。搜尋我只會爆搜打表,好像並沒有什麼高階搜尋技巧能做。
所以狀壓dp是最好的選擇(實際這道題就是狀壓dp的入門題)。
狀態壓縮,顧名思義就是把狀態通過2進製的方式存起來。在這道題中,對於每行棋盤的n個格仔,0代表不放國王,1代表放國王。打個比方,如果n=3,111代表3個格仔都放了國王(本題中這種情況不合理),101表示第乙個格仔和第三個格仔放了國王。
很顯然每種方案只會對應乙個唯一的十進位制的數,所以可以通過
接下來是dp陣列的建立。首先,狀壓dp有一維肯定表示狀態,然後再用一維表示行數,最後還要用一維表示已經放置的國王數。這個陣列
然後就是如何判斷狀態可行性的問題了。因為是從第一行往下列舉,所以第一行只需要判斷自己這一行是否合法。因為國王能攻擊左邊和右邊,所以對於狀態
對於之後的每行來說,除了剛才那種判斷,還要判斷是否和上一行狀態衝突。由於國王能攻擊左上,上,右上。假設當前行狀態為
所以在預處理好第一行之後,
列舉剩下的行數,當前行狀態,上一行狀態,放完當前行後已經放置的國王數。然後轉移就好了,轉移方程就直接看**吧。
#include#include#include#include#include#include#include#includeusing namespace std;
inline int read()
while(ch>='0'&&ch<='9')
return sum*t;
}void write(int x)
inline int getbit(int x)//雖然有o(1)的方法但是既然複雜度過得去還是o(logx)暴力比較方便
return sum;
}int n,k;
long long dp[11][105][1100];
long long ans=0;
int main()
BZOJ 1087, 互不侵犯
傳送門 給定一張大小為n n的棋盤,要求放置k個棋子,其中,棋子上下左右以及左上 左下 右上和右下八個位置不得有其它棋子存在。求合法方案數。動態規劃。狀態數很多,可以先預處理出一行的合法放置方案,再處理出上一行放置的情況下,下一行哪些方案是可行的,於是一行一行轉移即可。運用位運算優化預處理,後來四重...
BZOJ 1087( ) 互不侵犯
1087 scoi2005 互不侵犯king time limit 10 sec memory limit 162 mb submit 5333 solved 3101 submit status discuss description 在n n的棋盤裡面放k個國王,使他們互不攻擊,共有多少種擺放方...
BZOJ 1087 互不侵犯King
1087 scoi2005 互不侵犯king time limit 10 sec memory limit 162 mb description 在n n的棋盤裡面放k個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上 左下右上右下八個方向上附近的各乙個格仔,共8個格仔。i...