暑假集訓Day2 互不侵犯(狀壓dp)

2022-02-02 02:45:11 字數 1355 閱讀 5565

在n*n的棋盤裡面放k個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各乙個格仔,共8個格仔。

只有一行,包含兩個數n,k 。

所得的方案數。

1.顯然這又是一道狀壓的題

2.顯然一樣是用f陣列表示方案數

為什麼呢

我們首先分析一下f的轉移情況 f的狀態與什麼有關呢 首先我們很容易知道我們的dp是從上往下一點點遞推實現的 而這個國王會攻擊到自己的身旁八個位置

所以呢 那f就會對自己的下一行產生影響 而且只會對自己的下一行產生影響 換而言之 f只和自己上一行的狀態有關

這樣的話我們就會用到兩維,一維儲存前i行 另一維儲存狀態 但是看到這個題只用兩維是不夠的 因為這個題需要放置的國王個數恰好等於k

所以我們將前i行放置的國王個數作為一維

和平時的狀壓題一樣我們將狀態作為最後一維 所以關於f[i][j][k]的定義我們有前i行共放了j個國王而且第i行所放國王的狀態為k的方案數

所以我們就可以寫出這樣的狀態轉移方程

int sum(int x)

for(int i = 1;i <= n;++i)

for(int j = 0;j < maxs;++j)

}

這個**的注釋已經很清晰了

但是我們再具體分析一下思想(如果不理解sum函式的去翻暑假集訓day2 特殊方格棋盤)

首先我們枚舉行數

然後列舉本行的狀態

本行狀態與自己衝突的情況就是(j & (j<<1))為真 j有兩位二進位制位同時為1 那麼才可能(j&j<<1)為真

舉個栗子:j = 01100 那麼j<<1就是11000和j取與後並不等於0 所以衝突(即連續兩個格仔放置了國王,他們互相攻擊)

3.然後就要列舉上一行的狀態

關於本行與上一行狀態衝突的判定具體方法可參見上一條

劃重點: sum(j) 為當前行所放的國王個數,前i行的國王個數肯定就是大於等於這個數的 列舉前i行國王個數,然後減去sum(j)就是前i-1行共放的國王個數

因此f[i-1][s-sum(j)][k] 就是 前i-1行共s-sum(j)個國王並且第i-1行的國王個數為k的方案數

通過這個的累加就是我們的遞推過程

#includeusing namespace std;

long long f[10][100][1000],ans;//f[i][j][k]表示前i行放j個國王並且當前行狀態為k的成立方案數

int lowbit(int x)

int sum(int x)

int main()

} for(int i = 0;i < 1《點點關注

謝謝**》)<

互不侵犯 狀壓

在n x n 的棋盤裡面放 個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各乙個格仔,共 個格仔。1 n 9,0 k n x n 只有一行,包含兩個數 n,k。所得的方案數。3 216大家都做過玉公尺地吧,這其實和那道題很像,只是玉公尺地是上...

互不侵犯king 狀壓dp

在n n的棋盤裡面放k個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各乙個格仔,共8個格仔。1 le n le 9,0 le k le n n 這道題如果普通dfs肯定會超時。為什麼呢?我們發現一行中的狀態是固定的,同時行與行之間的衝突情況也...

狀壓dp SCOI 2005 互不侵犯

題意 在n n n nn n的棋盤裡面放k kk個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各乙個格仔,共8 88個格仔。考慮如何狀壓,對於每一行,我們用乙個長度為n nn的二進位制串表示每一行的狀態,比如1010 1010 1010 表示...