狀態壓縮DP

2021-09-25 05:12:17 字數 1700 閱讀 2500

theme:給定乙個n*m的玉公尺田,1<=n,m<=12。值為0表示不能在該塊種草,為1表示可以。現在要在其上中若干草地,要求任意草地間不相鄰(沒有公共邊),問不考慮草地個數的情況下,有多少種種植的方案?

solution:用dp。又範圍很小,所以考慮狀態壓縮dp,另dp[i][j]表示從前i行種植,最後一行的狀態為j時的方案數。其中狀態j:如m=3,最後一行這樣種:101表示第1,3塊種植,第2塊不種,則j=5。所以狀態轉移方程為:

for k:0->(1《如果與上一行種植情況不衝突,則dp[i][j] += dp[i-1][k]

首先怎麼判斷一行的種植情況是否合理,即是否有連續的草地:對於狀態i,如果 i&(i<<1)==0且i&(i>>1)==0,則說明沒有相鄰的。合理。

怎麼判斷上下兩行的狀態是否衝突,即是否有在同一列的:如果j&k==0說明沒有同時為1的,則合理。

由於有的位置輸入值為0,表示不能種植,所以輸入後預處理s陣列,表示輸入的該行的二進位制狀態,則當s[i]&j==j時表示j中不存在某一位為1而s[i]中改為為0.

#includeusing namespace std;

#define far(i,t,n) for(int i=t;i>n>>m;

far(i,1,n+1)

far(j,1,m+1)

scanf("%d",&a[i][j]);

far(i,1,n+1)

int es=1<>1))==0);

getdp(n,m);

ll ans=0;

far(i,0,es)

ans=(ans+dp[n][i])%p;

coutsolution:n很小,由n與m的特殊性,考慮用狀態壓縮dp,dp[i]表示買的書的狀態為i時最多優惠的**,因為要買所有n本書,則最終答案為dp[1#includeusing namespace std;

#define far(i,t,n) for(int i=t;i>n>>m;

int sum=0;

far(i,1,n+1)

scanf("%d",&price[i]),sum+=price[i];

sort(price+1,price+n+1,greater());

far(i,0,m)

vis[state]=1;

}int es=1<0;j=i&(j-1))

for(int j=0;jtheme:n首歌,給定每首歌的時長t1與分類gi,問共有幾種不同的選歌方式,使得每首歌最多被選1次,總的時長為t且相鄰兩首歌的類別不同。1≤n≤15,1≤t≤225,1<=gi<=3

solution:像這種n很小的選擇問題考慮狀態壓縮dp。用dp[s][i]表示狀態為s,最後一首歌的類別為i時的選擇方法,則每乙個dp[s][i]可以用來更新再選一首歌的情況,即:dp[s^(1#define far(i,t,n) for(int i=t;i>n>>t;

far(i,0,n)

cin>>t[i]>>g[i],g[i]--;

int ans=0;

dp[0][3]=1;

for(int s=0;s<=maxs-1;++s)

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

}int x=0;

far(j,0,n)

if(s&(1

if(x==t)

ans=(ans+dp[s][i])%p;

}cout<}

狀態壓縮DP

首先,我們以一道狀壓經典題tsp來引入。tsp問題 一張圖上有n個點,給定相應的鄰接矩陣,需要求出從0號節點出發,經過且只經過每個頂點一次,最後仍回到0號節點的最小邊權。思路 假設現在已訪問過的頂點集合 起點0當作還未訪問過的頂點 為s,當前所在頂點為v,用dp s v 表示從v出發訪問剩餘的所有頂...

狀態壓縮DP

總結狀壓dp轉移的方法 若某個狀態下可以對下 1.按二進位制讀入資料 2.列舉所有方案,如果合理 一行中沒有兩兩相鄰的 就儲存 i i 1 3.因為每一層的狀態只受上一層影響,因此迴圈兩次所有合理方案,為每乙個方案找到一系列下一層合理方案 4.遍歷每一行,並遍歷每一行的所有合理方案,若與預處理不矛盾...

dp 狀態壓縮

之前我們在討論的dp形式當中,大多數是對整數的動態規劃,然而對於集合而言呢 我們使用 dfs 嗎,看起來也可以,但是加上dp記憶 陣列的 動態規劃效率更高 那麼進一步討論,我們如何表示集合元素是否被使用的狀態呢 是通過康拓展開,next permutation 嗎?這個是全排列,是有些重複的,在 d...