狀壓DP入門題集錦

2021-07-10 07:23:05 字數 3327 閱讀 6988

poj 3254corn fields

題意:

一塊n*m的田,1表示這個地方可以種植,0代表這個地方不能種植。植物種植還必須滿足兩株植物不能相鄰(橫豎都不行)。問共有幾種種植方法,而且當什麼都不種時認為是一種方法。

解題思路:

種植用1表示,不種植用0表示。每一行的情況就可以用乙個二進位制數state來儲存。state的範圍是 [0 ~ 1<< state).

dp[i][state]表示第i行狀態為state的情況下滿足條件的數目。

狀態轉移方程為:dp[i][state] += dp[i-1][pre_state];這個state和pre_state必須滿足意義所給的條件,即左右不相鄰,上下不相鄰。那麼 第i行狀態為state的情況為第i-1行所有滿足條件的狀態為pre_state相加而成。

最後的答案為最後一行所有狀態的情況和相加而得。

位運算需要注意的地方:

1.注意打括號

2. 1 & (state>>i) 和 state & ( 1<< i ) 還是有差別的。 前者的答案只有0和1,而後者的答案有0和可能的正數。判斷的時候還是要注意下寫法

3. 當前行是否相鄰的判斷條件是: state & (state<<1) 是否為 0

4. 上下兩行是否相鄰的判斷條件是: state & pre_state 是否為 0

#include 

#include

#include

#include

using

namespace

std;

int dp[15][1

<<15];

bool is[15][15];

int n,m;

const

int mod = 1e8;

bool check(int x,int state)

}return

true;

}int main()

}if(i==n) ans = (ans + dp[i][j]) % mod;}}

printf("%lld\n",ans);

}return

0;}

poj 1185炮兵陣地

解題思路:

三維dp陣列來表示狀態的轉移。

dp[i][j][k]表示在第i行狀態為j且第x-1行狀態為k時的方案數。因為第i行放炮兵與第i-1行和i-2行相關。

這裡有個優化:對於每一行的狀態都有 1< < m 種可能,如果每個列舉會tle。其實每一行的最多狀態數也只有60種。因為m最大為10,且每3個不能相鄰,可列舉出來這60種情況。

#include 

#include

#include

#include

#include

using

namespace

std;

bool is[150][15];

int dp[110][1

<<11][1

<<11];

int n,m,t=0;

int can[150];

void init()

return;

}int check(int x,int state)

}return cnt;

}int main()

int ans = 0,now;

for(int i=1;i<=n;i++)}}

dp[i][can[j]][can[k]] += now;

if(i==n) ans = max(ans,dp[i][can[j]][can[k]]);}}

}}

printf("%d\n",ans);

return

0;}

poj 3311 hie with the pie

題意:

乙個送外賣的人,要將外賣全部送去所有地點再回到店離,求最短路。

解題思路:

旅行商問題。先用floyed得到每兩個點之間的距離,然後狀壓dp解決旅行商問題。

類似題目:

#include 

#include

#include

#include

using

namespace

std;

int path[15][15];

const

int inf = 0x3f3f3f;

int dp[15][1

<<15];

int n;

void floyed()

int main()}}

}int ans = inf;

for(int i=2;i<=n;i++)

cout

0;}

codeforce 580d kefa and dishes

題意:

有n盤菜,每盤菜都有乙個美味值。但是你只能選m盤菜。並且這些吃菜的順序能影響總美味值。如果i當且僅當在j之前吃,那麼會額外加一些美味值,這樣的組合有k組。求選m盤菜吃能獲得的最大的美味值。

解題思路:

dp[i][sta] 表示當前吃的菜是i,狀態為sta的情況。

更新總答案的時候在更新sta的時候可以獲得。

#include 

using

namespace

std;

typedef

long

long ll;

ll dp[20][1

<<18];

ll wei[20];

ll add[20][20];

int n,m,k;

bool check(int sta)

if( now == m) return

true;

return

false;

}int main()

memset(dp,0,sizeof(dp));

ll ans = 0;

for(int i = 1; i<(1

for(int k = 1;k<=n;k++)}}

}}

cout

0;}

狀壓DP入門題

學習狀壓之前必須要熟練掌握位運算 位運算名 符號效果 and 按位與如果兩個相應的二進位制位都為1,則該位的結果值為1,否則為0 l or 按位或兩個相應的二進位制位中只要有乙個為1,該位的結果值為1 xor 按位異或 單身狗操作 若參加運算的兩個二進位制位值相同則為0,否則為1 取反 一元運算子,...

狀壓DP入門

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

狀壓DP入門

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