#include<stdio.h>
#include<string.h>
int check(int a,int m)
{
int b=0;
while(a>0)
{
if(a&1)
b++;
a>>=1;
}
if(b==m)
return 1;
return 0;
}
int main()
{
int n,m,dp[(1<<8)+5][10],Map1[10],s[1000],len;//dp[i][j]定义状态为在j行的状态为i
char Map[10][10];
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n==0||m==0)
{
printf("0\n");
continue;
}
if(n==-1&&m==-1)
break;
for(int i=0; i<n; i++)
scanf("%s",Map[i]);
memset(Map1,0,sizeof(Map1));
for(int i=0; i<n; i++)//压缩地图
{
for(int j=0; j<n; j++)
if(Map[i][j]=='.')
Map1[i]=Map1[i]|(1<<(n-1-j));
}
len=0;
for(int i=0; i<(1<<n); i++)//把所有的有m个1的状态存到一个数组里
if(check(i,m))
s[len++]=i;
memset(dp,0,sizeof(dp));
for(int j=0;j<n;j++)//把所有为1个1的都都初始化为1,由这些点这些为只有一个1的状态去扩展,所以这个能用dp的本质是算出来所有一个情况,然后扩展成两个的情况,慢慢扩展,所以最后求一下题目要求的m的所有状态的和就行了
{
for(int i=1; i<(1<<n); i=(i<<1))
if((Map1[j]&i)==0)
dp[i][j]=1;
}
for(int i=1; i<n; i++)//枚举行
{
for(int j=0; j<(1<<n); j=j==0?1:j<<1)//直接枚举当前行的状态是0,1,2,4,8.(也就是只有一个1)
{
if((j&Map1[i])==0)//判断是否和地图矛盾
for(int k=0; k<(1<<n); k++)//枚举上一行的状态
if((k&j)==0)//判断两个状态是否矛盾,当j==0的时候表示当前行不放,当j不等于0的时候是放在那,所以当j放一个位置的时候无论扩展到那个一个状态,都等于1*dp[k][i-1]中情况所以直接加上就行
dp[k|j][i]+=dp[k][i-1];
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<(1<<n);j++)
printf("%d ",dp[j][i]);
puts("");
}
int ans=0;
for(int i=0; i<len; i++)
ans+=dp[s[i]][n-1];
printf("%d\n",ans);
}
return 0;
}
/*
4 3
#..#
#.#.
..#.
#.##
5 4
#..#.
#.#..
..#..
#.##.
.####
3 3
###
###
###
*/
/*
5 4
#.#.
##..
.#..
###.
.###
*/
POJ 1321 棋盘问题
最新推荐文章于 2022-07-29 20:54:45 发布