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...