狀壓DP入門題

2021-09-10 02:07:06 字數 3755 閱讀 1948

學習狀壓之前必須要熟練掌握位運算

位運算名

符號效果

&(and)

按位與如果兩個相應的二進位制位都為1,則該位的結果值為1,否則為0

l(or)

按位或兩個相應的二進位制位中只要有乙個為1,該位的結果值為1

^(xor)

按位異或(單身狗操作)

若參加運算的兩個二進位制位值相同則為0,否則為1~取反

一元運算子,用來對乙個二進位制數按位取\反,即將0變1,將1變0

<<

左移用來將乙個數的各二進位制位全部左移n位,右補0

>>

右移將乙個數的各二進位制位右移n位,移到右端 的低位被捨棄,對於無符號數,高位補0

下面是一些基本操作

動態規劃必須滿足無後效性原則,即則此階段以後過程的發展變化僅與此階段的狀態有關,而與過程在此階段以前的階段所經歷過的狀態無關。通俗來講也就是說i的狀態只能由i-1來決定

題目描述

農場主john新買了一塊長方形的新牧場,這塊牧場被劃分成m行n列(1 ≤ m ≤ 12; 1 ≤ n ≤ 12),每一格都是一塊正方形的土地。john打算在牧場上的某幾格里種上美味的草,供他的奶牛們享用。

遺憾的是,有些土地相當貧瘠,不能用來種草。並且,奶牛們喜歡獨佔一塊草地的感覺,於是john不會選擇兩塊相鄰的土地,也就是說,沒有哪兩塊草地有公共邊。

john想知道,如果不考慮草地的總塊數,那麼,一共有多少種種植方案可供他選擇?(當然,把新牧場完全荒廢也是一種方案)

輸入輸出格式

輸入格式:

第一行:兩個整數m和n,用空格隔開。

第2到第m+1行:每行包含n個用空格隔開的整數,描述了每塊土地的狀態。第i+1行描述了第i行的土地,所有整數均為0或1,是1的話,表示這塊土地足夠肥沃,0則表示這塊土地不適合種草。

輸出格式:

乙個整數,即牧場分配總方案數除以100,000,000的餘數

輸入輸出樣例

輸入樣例#1:

2 3

1 1 1

0 1 0

輸出樣例#1:

9
**
#include

#define mod 100000000

using

namespace std;

const

int m=

15,n=

1<<15;

int st[n]

,mp[m]

//存可行的不相鄰的狀態以及圖中每排的狀態;

int dp[m]

[n];

//存每排

int n,m;

int ans;

inline

intread()

while

(ch<=

'9'&&ch>=

'0')

return x*f;

}bool

judge1

(int x)

//判斷相鄰兩點是否衝突

bool

judge2

(int i,

int x)

//判斷點能不能放

intmain()

}int k=0;

for(

int i=

0;i<

;i++

)for

(int i=

1;i<=k;i++

)for

(int i=

2;i<=n;i++)}

}for

(int i=

1;i<=k;i++

)printf

("%d"

,ans)

;return0;

}

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

輸入輸出格式

輸入格式:

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

輸出格式:

所得的方案數

輸入輸出樣例

輸入樣例#1:

3 2

輸出樣例#1:

16

**

#include

using

namespace std;

const

int n=

10,m=

1<<10;

int st[m]

;//表示所有狀態

long

long f[n]

[m][n*n]

;//表示第i行,狀態為j,前面擺了k個國王時,方案數;

int king[m]

;//表示每個狀態所對應的國王數

int n,k;

inline

intread()

while

(ch>=

'0'&&ch<=

'9')

return x*f;

}bool

judge

(int x)

//兩個國王之間必須隔乙個,判斷是否滿足題意國王之間不相互攻擊;

intmain()

//判斷這個狀態有多少個國王,也就是t在二進位制下有多少個1;}}

//找出所有合法的狀態以及該狀態國王的數量

for(

int i=

1;i<=t;i++)if

(king[i]

<=k)

f[1][i]

[king[i]]=

1;//先處理第一行;

for(

int i=

2;i<=n;i++

)//處理剩下的,所以從 2 開始列舉;

for(

int j=

1;j<=t;j++

)//列舉當前行狀態;

for(

int l=

1;l<=t;l++

)//再一遍狀態,用來當作上一行的狀態,因為有效狀態轉移是從上一行開始的;

}long

long ans=0;

for(

int i=

1;i<=n;i++

)//不確定在哪一行用光國王,所以都列舉一遍;

for(

int j=

1;j<=t;j++

) ans+

=f[i]

[j][k]

;//本行及以前用光了國王,那麼方案數加在總數中;

printf

("%lld"

,ans)

;return0;

}`

狀壓DP入門題集錦

poj 3254corn fields 題意 一塊n m的田,1表示這個地方可以種植,0代表這個地方不能種植。植物種植還必須滿足兩株植物不能相鄰 橫豎都不行 問共有幾種種植方法,而且當什麼都不種時認為是一種方法。解題思路 種植用1表示,不種植用0表示。每一行的情況就可以用乙個二進位制數state來儲...

狀壓DP入門

洛谷題號p1896 在n n的棋盤裡面放k個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各乙個格仔,共8個格仔。題解 首先暴搜可肯定是超時的所以我門考慮狀壓 因為每個數都可以用二進位制表示出來 二進位制中01可以表示當前行放的棋子的位置 以及...

狀壓DP入門

首發於摸魚世界 狀壓dp,即狀態壓縮dp,它的精髓在於把dp過程中的乙個 狀態 用乙個二進位制數巧妙的表示出來。接下來就從一些入門的狀壓題目來感受一下狀壓的魅力吧 洛谷p5911 poi2004 prz 大致題意 n 個人過最大承載 w 重量的橋,每個人有重量 w i 與過橋時間 t i 多人一組時...