1. 程式人生 > >bzoj1725 [Usaco2006 Nov]Corn Fields牧場的安排(狀壓dp)

bzoj1725 [Usaco2006 Nov]Corn Fields牧場的安排(狀壓dp)

mit clas sample www earch 劃分 using nbsp 方程

1725: [Usaco2006 Nov]Corn Fields牧場的安排

Time Limit: 5 Sec Memory Limit: 64 MB
Submit: 714 Solved: 502
[Submit][Status][Discuss]

Description

Farmer John新買了一塊長方形的牧場,這塊牧場被劃分成M列N行(1<=M<=12; 1<=N<=12),每一格都是一塊正方形的土地。FJ打算在牧場上的某幾格土地裏種上美味的草,供他的奶牛們享用。遺憾的是,有些土地相當的貧瘠,不能用來放牧。並且,奶牛們喜歡獨占一塊草地的感覺,於是FJ不會選擇兩塊相鄰的土地,也就是說,沒有哪兩塊草地有公共邊。當然,FJ還沒有決定在哪些土地上種草。 作為一個好奇的農場主,FJ想知道,如果不考慮草地的總塊數,那麽,一共有多少種種植方案可供他選擇。當然,把新的牧場荒廢,不在任何土地上種草,也算一種方案。請你幫FJ算一下這個總方案數。

Input

* 第1行: 兩個正整數M和N,用空格隔開

* 第2..M+1行: 每行包含N個用空格隔開的整數,描述了每塊土地的狀態。輸入的第i+1行描述了第i行的土地。所有整數均為0或1,是1的話,表示這塊土地足夠肥沃,0則表示這塊地上不適合種草

Output

* 第1行: 輸出一個整數,即牧場分配總方案數除以100,000,000的余數

Sample Input

2 3
1 1 1
0 1 0


Sample Output

9

輸出說明:

按下圖把各塊土地編號:

1 2 3
4

只開辟一塊草地的話,有4種方案:選1、2、3、4中的任一塊。開辟兩塊草地的話,有3種方案:13、14以及34。選三塊草地只有一種方案:134。再加把牧場荒廢的那一種,總方案數為4+3+1+1=9種。

Source

Gold

/*
都說狀壓裸題,可我感覺好難的樣子......
f[i][j]表示第i行狀態為j時的方案數
1.39~43行 預處理每行狀態(二進制,若狀態和裏有2^i,說明i號格子可以種)
2.19~23行 判斷第一行的可行狀態 相鄰不能都種 && 枚舉出來的狀態可達 f[1][i]=1;
3.25~32行 dp 枚舉行和每行狀態 若上一行j狀態可達,就轉移,枚舉轉移到的狀態k。
判斷:  與上面不相同:(j&k)==0;  與右邊不相同: (k&(k>>1))==0  狀態可達: (k|mp[i])==mp[i]
方程:  f[i][k]=(f[i][k]+f[i-1][j])%mod;
4.37行  累加每一行答案 
*/ #include<iostream> #include<cstdio> #include<cstring> #define mod 100000000 using namespace std; int mp[13],f[13][4096]; int ans,ed,n,m,x; void dp() { for(int i=0;i<=ed;i++) { if((i&(i>>1))==0 && (i|mp[1])==mp[1]) f[1][i]=1; } for(int i=2;i<=m;i++) for(int j=0;j<=ed;j++) { if(f[i-1][j]) for(int k=0;k<=ed;k++) { if((j&k)==0 && (k|mp[i])==mp[i] && (k&(k>>1))==0) f[i][k]=(f[i][k]+f[i-1][j])%mod; } } for(int i=0;i<=ed;i++) ans+=f[m][i],ans%=mod; } int main() { scanf("%d%d",&m,&n); for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) { scanf("%d",&x); mp[i]<<=1;mp[i]+=x; } ed=(1<<n)-1;dp(); printf("%d\n",ans); return 0; }

bzoj1725 [Usaco2006 Nov]Corn Fields牧場的安排(狀壓dp)