在了解狀壓dp之前,首先要了解簡單的位運算。
型別符號
規則例子與&
同1為1,其餘為0
11&3= 00001011&00000011 = 00000011 = 3
向左位移
<<
向左移一位,右邊自動補0
11<<1 = 00001011<<1 = 00010110 = 22
向右位移
_>>
向右移一位,左邊自動補1
11>>1 = 00001011>>1 = 00000101 = 5
我們先看一道入門題來講解狀壓dp。
題目描述
john租了一片矩形農場,農場由m(1 <= m <= 12)行n(1 <= n<= 12)列的方格構成。有的方格土地肥沃,可以種植莊稼;有的方格土地貧瘠,則不可以種植。同時,為了讓作物長得好,乙個種了作物的方格相鄰的(上下左右共四個)方格不可以種植。他希望知道一共由多少種不同的種植方案。
輸入
第一行是兩個數m和n
接下來的m行每行n個數,每個數代表當前位置是否可以種植,1表示可以,0表示不可以。
輸出
輸出一行,包含乙個整數,代表總的種植方案的個數對100000000取模後的值。
樣例輸入
2 3
1 1 1
0 1 0
樣例輸出
9題目解析
狀壓dp全稱狀態壓縮dp,指的是根據題目情況和資料範圍壓縮陣列的維度。對於本題,常見的方法是將每一行的方格肥沃狀態以及作物可能的種植狀態用二進位制表達,再壓縮為十進位制。
以樣例輸入舉個例子:
1 1 1
0 1 0
第一行
肥沃狀態:111->7
作物可種植狀態:
000->0(都不種)
001->1
010->2
100->4
101->5
第二行
肥沃狀態:010->2
作物可種植狀態:
000->0(都不種)
010->2
那麼如何將兩行合併在一起呢?
設dp[i][j]代表當第i行取j狀態時,種植作物的最大值。對於第一行,可取的狀態有0,1,2,4,5;對於第二行,可取的狀態有0,2。我們對於這些可取的狀態進行列舉計算是否矛盾。
首先第一行是0,第二行也是0。解壓後可得
000
000
很明顯在這種狀態下,並沒有作物是相鄰的。
然後第一行還是0,第二行取2。解壓後可得
000
010
也沒有作物相鄰。
直到第一行是2,第二行也是2。解壓後發現
010
010
第二列的作物相鄰了!
位運算此時可以大顯神威了:設兩個狀態沒有相鄰作物為0,否則為1。在與運算(&)中,同1為1,其餘為0。000&000=0,000&010=0,010&010=1。因此狀態轉移方程為:dp[i][j]+=dp[i-1][k]。這裡的k代表不與狀態j矛盾的狀態。如何判斷兩個狀態是否矛盾前面已經提到過了。
下面是**
題目**
//cur[i]代表第i行方格肥沃狀態
//state儲存本身合法的狀態,暫時不考慮方格肥沃狀態
//如000,010等合法;110,011等由於作物已經相鄰不合法
//total代表狀態的總數量
//top記錄本身合法狀態的總數量
//dp已經提到過
#include
#include
#define mod 100000000
using
namespace
std;
int state[600],cur[13],top=0;
int dp[13][600];
int n,m;
void init()//初始化state
int main()
for(int i=1;i<=top;i++)
if(!(state[i]&cur[1]))dp[1][i]=1;//初始化dp
for(int i=1;i<=m;i++)//三重迴圈 首先枚舉行
for(int j=1;j<=top;j++)//然後列舉本身合法狀態
}int ans=0;
for(int i=1;i<=top;i++)
ans=(ans+dp[m][i])%mod;//不解釋了,都應該看得懂
cout
0; }
題解 poj3254 狀壓DP
題目鏈結 思路摘抄自大佬部落格 狀態可由二進位制表示,只需將每種狀態轉化為相應的十進位制數,即可只用乙個數字,就能表示某一種狀態 以dp i state j 來表示對於前i行,第i行採用第j種狀態時可以得到的可行方案總數!例如 回頭看樣例資料,dp 2 1 即代表第二行使用第2中狀態 0 1 0 時...
poj3254 基礎狀壓dp
第二個狀壓dp 做過的第乙個也是放牛問題,兩頭牛不能相鄰 這個題多了乙個限制,就是有些位置不能放牛 於是先與處理一下每一行所有不能放牛的狀態,處理的過程直接對每乙個不能放牛的狀態或以下 ac include include include include include include using ...
狀壓DP入門
洛谷題號p1896 在n n的棋盤裡面放k個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各乙個格仔,共8個格仔。題解 首先暴搜可肯定是超時的所以我門考慮狀壓 因為每個數都可以用二進位制表示出來 二進位制中01可以表示當前行放的棋子的位置 以及...