状态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; }