SCOI 2005 互不侵犯

2022-03-20 04:57:49 字數 1710 閱讀 4044

洛谷傳送門

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

注:資料有加強(2018/4/25)

只有一行,包含兩個數n,k ( 1 <=n <=9, 0 <= k <= n * n)

所得的方案數

輸入 #1複製

輸出 #1複製

原諒我一開始看到題還以為是爆搜。。。

其實是一道狀態壓縮的題目。

蒟蒻自己乙個比較大的進步就是把自己狀態設定對了...

設定:\(dp[i][j][k]\)為第\(i\)行狀態為\(j\)、已經用了\(k\)個國王時的方案數。

狀態壓縮大體有這麼幾步:設定狀態\(\rightarrow\)考慮轉移方式\(\rightarrow\)按轉移方式考慮預處理和判斷轉移條件\(\rightarrow\)開始轉移\(\rightarrow\)統計答案。

那麼我們設定好狀態,開始考慮轉移方式:我們發現,若是想從第\(i-1\)行開始轉移,轉移的條件一是當前和上一次的狀態,但是,這些狀態的改變必然還會改變國王的個數。也就是說,這陣列的兩維是有聯絡的,是自變數和因變數的關係。所以我們因此想到,既然是自變數和因變數的關係,我們莫不如由此構建乙個對映,存下來每個狀態和每個狀態需要的國王人數。這樣我們轉移的時候就沒啥問題了。

如何預處理呢?我們想到,我們需要按行處理狀態,每個狀態有放國王和不放國王兩種選擇。因為是預處理,我們是肯定不能用遞推和\(dp\)的(你想幹啥)

所以我們考慮搜尋。

一次搜尋可以處理出所有合法的行的方式。

這裡插一嘴,因為我們已經把所有合法的行的方式都求出來了,所以我們沒必要再把\(dp\)陣列的第二維開那麼大,構建好對映關係之後,直接用\(cnt\)代替這個二進位制狀態即可。(因為\(1-cnt\)的每個數都對應著乙個陣列\(s[i]\)作為狀態。)

然後再轉移的時候進行判斷是否合法就可以。

轉移方程:

\[dp[i][j][l]+=dp[i-1][k][l-num[j]]

\]這裡的\(k,j\)分別表示一種狀態。

**:

#include#define int long long

using namespace std;

int n,k,cnt,ans;

int s[100],num[100];

int dp[10][100][110];

//dp[i][j][k]表示前i-1行放完,第i行狀態為j、有k個國王時的方案數

//狀態0/1:0:國王攻擊不到;1:被國王占領

void dfs(int pos,int st,int tot)

dfs(pos+1,st,tot);

dfs(pos+2,st+(1<>1))

continue;

else if(s[j]&(s[k]<<1))

continue;

else

for(int l=num[j];l<=k;l++)

dp[i][j][l]+=dp[i-1][k][l-num[j]];

}ans=0;

for(int i=0;i<=cnt;i++)

ans+=dp[n][i][k];

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的題是乙個套路 具體實現也基本一樣 就是記錄的狀態...