https://vjudge.net/problem/POJ-1321
思路:状压
d
p
dp
dp,设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示到第
i
i
i行且列状态为
j
j
j时的方案数,如果第
i
i
i行不放棋子,那么
d
p
[
i
]
[
j
]
+
=
d
p
[
i
−
1
]
[
j
]
dp[i][j]+=dp[i-1][j]
dp[i][j]+=dp[i−1][j];否则假设在第
x
x
x列放一个棋子,那么如果
j
&
(
1
<
<
x
)
&
m
a
p
[
i
]
[
j
]
=
′
#
′
j\&(1<<x)\&map[i][j]='\#'
j&(1<<x)&map[i][j]=′#′(其实就是判断
x
x
x列能否放置棋子),则有
d
p
[
i
]
[
j
]
+
=
d
p
[
i
−
1
]
[
j
x
o
r
(
1
<
<
x
)
]
dp[i][j]+=dp[i-1][j\ xor\ (1<<x)]
dp[i][j]+=dp[i−1][j xor (1<<x)]。
#include<cstdio>
#include<cstring>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
int dp[10][1005];
char s[10][10];
int main()
{
int n,k;
while(~scanf("%d%d",&n,&k)&&n!=-1&&k!=-1)
{
for(int i=0;i<n;i++)
scanf("%s",s[i]);
memset(dp,0,sizeof(dp));
int nn=1<<n;
dp[0][0]=1; //第一排什么都不放的情况
for(int i=0;i<n;i++) //第一排放1个的情况
if(s[0][i]=='#')
dp[0][1<<i]=1;
for(int i=1;i<n;i++)
{
for(int j=0;j<nn;j++)
{
dp[i][j]+=dp[i-1][j];//i行一个也不放
for(int x=0;x<n;x++) //假设放在第x列
if(s[i][x]=='#'&&j&(1<<x))
dp[i][j]+=dp[i-1][j^(1<<x)];
}
}
int ans=0;
for(int i=0;i<nn;i++)
if(__builtin_popcount(i)==k)
ans+=dp[n-1][i];
printf("%d\n",ans);
}
return 0;
}