[USACO06NOV]玉米田Corn Fields 状压DP
题面:
农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列(1 ≤ M ≤ 12; 1 ≤ N ≤ 12),每一格都是一块正方形的土地。John打算在牧场上的某几格里种上美味的草,供他的奶牛们享用。
遗憾的是,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,于是John不会选择两块相邻的土地,也就是说,没有哪两块草地有公共边。
John想知道,如果不考虑草地的总块数,那么,一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)
输出一个整数,即牧场分配总方案数除以100,000,000的余数。
题解:
emmm。。。一道不难的状压DP
设f[i][j]表示到i行,状态为j的方案数,
因为相邻两块土地不能选,所以我们可以先dfs搜出所有可能状态,
这样状态数暴跌10倍,,,貌似很划得来的样子,不过不这样好像也可以,但是DP判断的地方也会麻烦一些。。。
然后存下不能放的地方,并标记为1,(同样用状压)
依次枚举行,当前状态,上一行状态,统计并取模即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define AC 15 5 #define LL long long 6 #define mod 100000000 7 int n,m,tmp,ans,tot; 8 int f[AC][400],s[AC],num[400];//error!!!状态要开400,,, 9 10 11 void pre() 12 { 13 int a; 14 scanf("%d%d",&n,&m); 15 for(R i=1;i<=n;i++) 16 for(R j=1;j<=m;j++) 17 { 18 scanf("%d",&a); 19 if(!a) s[i] |= 1 << (m - j);//给定状态也要压 20 } 21 } 22 23 void dfs(int x,int now) 24 { 25 if(x) tmp+=1 << (m - now); 26 if(now == m) 27 { 28 num[++tot]=tmp; 29 if(x) tmp-=1 << (m - now); 30 return ; 31 } 32 if(x) dfs(0,now+1); 33 else 34 { 35 dfs(0,now+1); 36 dfs(1,now+1); 37 } 38 if(x) tmp-=1 << (m - now); 39 } 40 41 void work() 42 { 43 for(R i=1;i<=tot;i++)//第一行特殊处理 44 { 45 if(s[1] & num[i]) continue; 46 f[1][i]=1; 47 } 48 for(R i=2;i<=n;i++)//枚举行 49 { 50 for(R j=1;j<=tot;j++)//枚举当前行状态 51 { 52 if(s[i] & num[j]) continue; 53 for(R k=1;k<=tot;k++)//枚举上一行状态 54 { 55 if(s[i-1] & num[k]) continue; 56 if(num[j] & num[k]) continue; 57 f[i][j] += f[i-1][k]; 58 f[i][j] %= mod; 59 //if(f[i][j] > mod) f[i][j] -= mod; 60 } 61 } 62 } 63 for(R i=1;i<=tot;i++) 64 { 65 ans+=f[n][i]; 66 ans%=mod; 67 //if(ans > mod) ans-=mod; 68 } 69 printf("%d\n",ans); 70 } 71 72 int main() 73 { 74 // freopen("in.in","r",stdin); 75 pre(); 76 dfs(1,1);//获取所有有效状态 77 dfs(0,1); 78 work(); 79 //fclose(stdin); 80 return 0; 81 }