在n×n
n×nn×
n的棋盤裡面放k
kk個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各乙個格仔,共8
88個格仔。(
n<=9
,k
<=n
∗n
)(n<=9,k<=n*n)
(n<=9
,k<=n
∗n)首先暴搜肯定被否定,時間複雜度是指數級的,所以我們就可用上狀態壓縮dpdp
dp啦。那什麼是狀態壓縮?在這題中按照我的理解就是將一行的所有擺放狀態看成不同的01
0101
串,然後將這些01
0101
串看成二進位制數,這樣每乙個擺放狀態就有乙個01
串01串
01串(二進位制數)與其對應。
假設1
11行有4
44個格仔,我們在第1、3
1、31、
3個格仔放棋子,2、4
2、42、
4不放棋子,然後我們定義乙個01
0101
串′ 1′
'1'′1
′表示此處有棋子,′0′
'0'′0
′表示沒有棋子,那麼這個01
0101
串就是1010
1010
1010
。那麼這樣子做有什麼好處?我的答案是操作起來十分方便和節省空間。為什麼方便?因為二進位制下對於這些狀態運用位運算十分好操作。
對於這題我們如何操作?我們可以先預處理第一行的所有可行狀態以及可行狀態can
[i
]can[i]
can[i]
所需的棋子數num
[i
]num[i]
num[i]
,然後根據題目所給條件一直往下遞推。
轉移方程:dp[
i][j
][l]
+=dp
[i−1
][p]
[l−n
um[j
]]
dp[i][j][l]+=dp[i-1][p][l-num[j]]
dp[i][
j][l
]+=d
p[i−
1][p
][l−
num[
j]]。
其中i
ii是當前行,j
jj是當前狀態,p
pp是上一行的可行狀態,l
ll是當前狀態所需的棋子數,所以l
ll從l−n
um[j
]l-num[j]
l−num[
j]而來。如何判斷題目所給的8
88個方向上是否有衝突?因為我們是從上往下遞推,所以在考慮當前行時僅用考慮此格仔的上下左右和左上右上,不需要考慮左下右下。
我們同樣可以預處理一行中的所有狀態,將相鄰的狀態全部否定,那麼我們在遞推的時候就不用考慮這些狀態了。考慮位運算。
假設上一行狀態y
yy,本行狀態xxx。
同行的判斷:如果乙個二進位制數x
xx有相鄰的1
11(棋子),那麼 (
x<
<1)
&x
(x<<1)\&x
(x<
<1)
&x必定不等於000。
左上右上的判斷:我們直接讓x
xx左移或右移一位再&
\&&上y
yy如果不等於0
00則衝突。((x
<
<1)
&y
)((x<<1)\&y)
((x<
<1)
&y)!=0
!=0!=
0,((
x>
>1)
&y
)((x>>1)\&y)
((x>
>1)
&y)!=0
!=0!=
0。正上方的判斷:(x&
y)
(x\&y)
(x&y)!=0
!=0!=
0遞推完後,我們加上最後一行擺放有k
kk個子的狀態的方案數就好了。
知道了這些這題就很簡單 了。
#include
using
namespace std;
typedef
long
long ll;
int n, k, maxsta;
ll ans, num[
1<<10]
, dp[10]
[1<<10]
[10*10
];bool can[
1<<10]
;int
main()
}}for(
int i =
0; i < maxsta; i++)if
(can[i]
&& num[i]
<= k)
dp[1]
[i][num[i]]=
1;//預處理第一行
for(
int i =
2; i <= n; i++)}
}}for(
int i =
0; i < maxsta; i++
) ans +
= dp[n]
[i][k]
; cout << ans <<
'\n'
;return0;
}
蒟蒻的第一題狀壓dpdp
dp,不容易啊。
P1896 互不侵犯 狀壓DP
目錄題目 分析變數定義 剔除左右相鄰的狀態 計算king state 如何動態規劃?如何表示限制條件 原博主的 寫在最後 在n n的棋盤裡面放k個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各乙個格仔,共8個格仔。輸入格式 只有一行,包含兩個...
互不侵犯(洛谷P1896)
題目 在n n的棋盤裡面放k個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各乙個格仔,共8個格仔。輸入輸出 輸入n,k,輸出有幾種放置方法。n 9,k n 2 樣例輸入輸出 入 3 2 出 16 這道題看範圍就顯然是狀壓dp了吧。其實這道題和...
洛谷 1896 互不侵犯
在n n的棋盤裡面放k個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各乙個格仔,共8個格仔。注 資料有加強 2018 4 25 只有一行,包含兩個數n,k 1 n 9,0 k n n 所得的方案數 輸入 1複製 3 2 輸出 1複製 16 題...