给出一个(m imes n)的矩形网格图,给出网格图中障碍物的位置,求向其中放若干个棋子互不相邻(当然也可以没有)的方案数(mod 10^8),(n,m imes 12)。
解
显然数据范围很小,考虑进制压缩,于是设(f[i][j])表示前i行,第i行状态为j的方案数,其中j有1的位置表示有棋子,可以先预处理出一行摆棋子合法的方案,记做(a[i][j])表示第i行第j个合法状态,因此有
[f[i][j]=sum_{k=1}^{|a[i]|}f[i-1][k](!a[i][k]&a[i-1][k])
]
边界:(f[0][1]=a[0][1]=0)
答案:(sum_{i=1}^{|a[m]|}f[m][i])
参考代码:
#include <iostream>
#include <cstdio>
#define il inline
#define ri register
#define cjx 100000000
using namespace std;
char c[13];
int dp[13][4097],a[13][4097],
at[13];
il void get(char&);
int main(){
int n,m,li;scanf("%d%d",&n,&m);
li=(1<<m)-1;
for(int i(1),j,k;i<=n;++i){
for(j=0;j<m;++j)get(c[j]);
for(j=0;j<=li;++j){
for(k=m-1;k>=0;--k)
if(j>>k&1){
if(c[k]=='0')break;
if(j>>(k+1)&1)break;
}
if(k<0)a[i][++at[i]]=j;
}
}++at[0],dp[0][1]=1;
for(int i(1),j,k;i<=n;++i)
for(j=at[i];j;--j)
for(k=at[i-1];k;--k){
if(a[i][j]&a[i-1][k])continue;
dp[i][j]+=dp[i-1][k];
if(dp[i][j]>cjx)dp[i][j]-=cjx;
}int ans(0);
for(int i(1);i<=at[n];++i)
(ans+=dp[n][i])%=cjx;printf("%d",ans);
return 0;
}
il void get(char &c){
while(c=getchar(),c==' '||c=='
'||c=='
');
}