bzoj1725 [Usaco2006 Nov]Corn Fields牧場的安排(狀壓dp)
阿新 • • 發佈:2017-07-13
mit clas sample www earch 劃分 using nbsp 方程
Submit: 714 Solved: 502
[Submit][Status][Discuss]
1 1 1
0 1 0
輸出說明:
按下圖把各塊土地編號:
1 2 3
4
只開辟一塊草地的話,有4種方案:選1、2、3、4中的任一塊。開辟兩塊草地的話,有3種方案:13、14以及34。選三塊草地只有一種方案:134。再加把牧場荒廢的那一種,總方案數為4+3+1+1=9種。
1725: [Usaco2006 Nov]Corn Fields牧場的安排
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 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 31 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)