状态DP的入门题,个人理解,状态DP实质是用2进制(或N进制)表示合法解,暴利枚举所有合法解的情况,然后统计。
具体算法,不再复述,网上各种总结,各种详细,各种给力。
代码出自dooder_daodao之手,贴来理解+YM:
#include<cstdio>
#define Legal(x) (x&(x<<1))?0:1
#define MOD 100000000
int map[16],legal[378],dp[16][378];
int main(){
int n,m,i,j,ls,c,h;
scanf("%d%d",&n,&m);
for(ls=i=0;i<(1<<m);i++) Legal(i)?(legal[ls++]=i):(j=0); //j=0 实质上是空操作
for(i=0;i<n;i++){
for(j=0;j<m;j++){
scanf("%d",&c);
map[i]|=(!c)<<j; //这里map存的是 非,即相反情况
}
}
for(i=0;i<ls;i++) //因为map存的是反,所以 按位与 为 0 时表示两者完全相同,
dp[0][i]=!(legal[i]&map[0]); //也就是说这种情况满足题目要求,dp[][]取1,否则取0
for(h=1;h<n;h++){
for(i=0;i<ls;i++){
if(legal[i]&map[h]) //legal[]保存的是所有可能的且合法的摆放方案,
continue; //只有当map[h]属于其中一种时,我们才去枚举
for(j=0;j<ls;j++){
if(legal[j]&legal[i])continue; //相邻两行的对应位置的点的0,1状态不能相同
dp[h][i]+=dp[h-1][j];
dp[h][i]%=MOD;
}
}
}
for(h=i=0;i<ls;i++){
h+=dp[n-1][i];
h%=MOD;
}
printf("%d\n",h%MOD);
return 0;
}