題解 P1896 SCOI2005 互不侵犯

2022-06-12 01:36:08 字數 1108 閱讀 6976

link

給定乙個 \(n\times n\) 的棋盤,在其中放置 \(k\) 個國王,使這些國王相互無法攻擊,求方案數。

國王能攻擊到與它八連通(與這個格仔有公共定點的)的任意乙個格仔。

\(1 \leq n \leq 9 ,1 \leq k \leq n^2\)

發現 \(n\) 非常小,並且一行的放置會不會有衝突之和上一行有關,考慮狀壓 dp 。

設 \(f_\) 表示前 \(i\) 行放置 \(j\) 個國王,且第 \(i\) 行的放置狀態是 \(k\) 的方案數。

狀態的屬性: \(\mathcal\) 。

轉移的時候可以列舉上一行的狀態 \(p\) ,設 \(vaild(i,j)\) 表示 \(i,j\) 能不能放在相鄰兩行,則有:

\[f_ = \sum_ f_

\]邊界: \(f_=0\) 。

目標: \(\sum_i f_\) 。

其中 \(count(x)\) 表示在狀態是 \(x\) 的一行放置了幾個國王(二進位制中 \(1\) 的個數)。

分析一下複雜度: \(\mathcal(nk2^n2^n)=\mathcal(nk4^n)\) 。

我們可以發現,在同一行裡,有很多狀態是不合法的,我們可以預處理出所有合法的狀態,列舉的時候直接列舉合法的狀態就可以。

同一行內合法的狀態大概有 \(150\) 個,所以總複雜度為 \(\mathcal(nk150^2)\) 。

**如下:

#include #include #include typedef long long ll;

inline bool check(int x)

inline bool check(int x ,int y)

inline int lowbit(int x)

inline int count(int x)

const int n = 15 ,s = 155 ,k = 105;

ll f[n][k][s]; //記得開 long long

int n ,m ,s[s] ,bin[s] ,idx; //s 儲存所有合法的狀態 ,bin 儲存每個狀態中 1 的個數。

signed main()

P1896 SCOI2005 互不侵犯

p1896 scoi2005 互不侵犯 資料不大,時間複雜度很高也差不多能過。使用狀壓dp dp i j k 表示到第i行,狀態為j,選了k個人 然後就是轉移,轉移的難點就是快速判斷 判斷的話,我們整體考慮。然後乙個狀態是否有相鄰的國王。用它本身按位與它本身右移 左移 若結果為0,則說明無相鄰的國王...

P1896 SCOI2005 互不侵犯

首先,養成乙個思路 資料這麼小?狀壓dp!然後翻題解可以這麼定義狀態 定義 dp i j k 為前 i 行中,第 i 行狀態為 j 前 i 行已放置 k 個國王的方案數。顯然一行的狀態只與前一行的有關,所以只需要記錄一行的狀態。但是一行的狀態好像很難存啊!難道複製乙個陣列進去嗎?其實,對於每乙個點,...

P1896 SCOI2005 互不侵犯

在n n的棋盤裡面放k個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各乙個格仔,共8個格仔。注 資料有加強 2018 4 25 只有一行,包含兩個數n,k 1 n 9,0 k n n 所得的方案數 輸入樣例 1 複製3 2 輸出樣例 1 複製...