【题解】洛谷P1879 [USACO06NOV] Corn Fields(状压DP)
洛谷P1879:https://www.luogu.org/problemnew/show/P1879
思路
把题目翻译成人话
在n*m的棋盘 每个格子不是0就是1
1表示可以种 0表示不能种 相邻的格子不能同时种 求总方案数
把每行看成一个n位的2进制数 预处理出每行的状态后 进行DP即可
PS:在处理每行的初始状态时 将其取反后更好操作
代码
#include<iostream> #include<cstdio> using namespace std; #define mod 100000000 int f[15][1010]; int n,m,ans; struct State { int st[5000]; int num; }a[15]; void getstate(int i,int t) { int num=0;//记录此行有几种状态 for(int j=0;j<(1<<n);j++)//枚举所有状态 { if((j&t)||(j&(j<<1))||(j&(j>>1))) continue;//如果冲突就跳过 a[i].st[++num]=j;//记录状态 a[i].num=num; } } void dp() { for(int i=1;i<=a[1].num;i++) f[1][i]=1;//初始化 for(int i=2;i<=m;i++)//枚举行 { for(int j=1;j<=a[i].num;j++)//枚举第i行的状态 { f[i][j]=0; for(int k=1;k<=a[i-1].num;k++)//枚举第i-1行的状态 { if(a[i].st[j]&a[i-1].st[k]) continue;//如果冲突就跳过 f[i][j]+=f[i-1][k];//累计ans } } } for(int i=1;i<=a[m].num;i++) ans=(ans+f[m][i])%mod;//累计第m行的所有状态的ans printf("%d",ans); } int main() { scanf("%d%d",&m,&n); for(int i=1;i<=m;i++) { int t=0;//处理当前行的状态 for(int j=1;j<=n;j++) { int x; cin>>x;//这里对输入进行取反操作 t=(t<<1)+1-x;//如1010 存成0101 方便后面判断状态 } getstate(i,t);//获得此行状态 } dp(); }