刷題總結——bzoj1725(狀壓dp)
題目:
題目描述
Farmer John 新買了一塊長方形的牧場,這塊牧場被劃分成 N 行 M 列(1<=M<=12; 1<=N<=12),每一格都是一塊正方形的土地。
FJ 打算在牧場上的某幾格土地裏種上美味的草,供他的奶牛們享用。遺憾的是,有些土地相當的貧瘠,不能用來放牧。並且,奶牛們喜歡獨占一塊草地的感覺,於是 FJ 不會選擇兩塊相鄰的土地,也就是說,沒有哪兩塊草地有公共邊。當然,FJ 還沒有決定在哪些土地上種草。
作為一個好奇的農場主,FJ 想知道,如果不考慮草地的總塊數,那麽,一共有多少種種植方案可供他選擇。當然,把新的牧場荒廢,不在任何土地上種草,也算一種方案。請你幫 FJ 算一下這個總方案數。
輸入格式
第 1 行: 兩個正整數 N 和 M ,用空格隔開
第 2..N+1 行: 每行包含 M 個用空格隔開的整數,描述了每塊土地的狀態。輸入的第 i+1 行描述了第 i 行的土地。所有整數均為 0 或 1 ,是 1 的話,表示這塊土地足夠肥沃,0 則表示這塊地上不適合種草。
輸出格式
輸出一個整數,即牧場分配總方案數除以 100,000,000 的余數。
樣例數據 1
輸入 [復制]
2 3
1 1 1
0 1 0
輸出
9
備註
【樣例說明】
土地情況如下:
1 | 1 | 1 |
0 | 1 | 0 |
按下圖把肥沃的各塊土地編號:
1 | 2 | 3 |
0 | 4 | 0 |
只開辟一塊草地的話,有 4 種方案:選 1、2、3、4 中的任一塊。
開辟兩塊草地的話,有 3 種方案:13、14 以及 34。
選三塊草地只有一種方案:1、3、4。
再加把牧場荒廢的那一種,總方案數為 4+3+1+1=9 種。
【數據範圍】
對於 50% 的數據,滿足1≤N≤5;1≤M≤6
對於 100% 的數據,滿足1≤N≤12;1≤M≤12。
題解:
狀壓dp裸題,用dp[i][j]表示處理到第i行,第i行狀態為j的方案數,dp[1][j]可以預處理出來,每次處理dp[i][k]時先枚舉dp[i-1][j]是否符合條件,再看k和j是否符合條件(詳細見代碼)
代碼:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<ctime> #include<cctype> #include<cstring> #include<string> #include<algorithm> using namespace std; const int mod=1e8; const int N=15; int map[N],dp[N][5000],n,m,maxx,ans; void Dp() { for(int i=0;i<=maxx;i++) if((i&(i>>1))==0 && (i|map[1])==map[1]) dp[1][i]=1; for(int i=2;i<=n;i++) for(int j=0;j<=maxx;j++) if(dp[i-1][j]) for(int k=0;k<=maxx;k++) { if((k&j)==0&&(k&(k>>1))==0&&(k|map[i])==map[i]) dp[i][k]=(dp[i][k]+dp[i-1][j])%mod; } for(int i=0;i<=maxx;i++) ans=(ans+dp[n][i])%mod; } int main() { //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); int a; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { scanf("%d",&a); map[i]=(map[i]<<1)+a; } maxx=1; for(int i=1;i<=m;i++) maxx=(maxx<<1); maxx--; Dp(); cout<<ans<<endl; return 0; }
刷題總結——bzoj1725(狀壓dp)