题目描述:在一个N*N的棋盘上放棋子,每一个棋子的上下左右都没有棋子,也就是不相邻,一共有多少种放法?(N <= 8)
sample_input
0
1
3
sample_output
1
2
63
分析:首先,我们可以逐行来摆放这些棋子,这样我们会发现,每一行的摆放状态只和上一行有关,这样我们可以采用递推
的方式来解决。
假设f[i][j]为第i行的摆放状态为j时的摆放总数(j表示所有满足条件的单行状态,如01001二进制表示0表示不放,1表
示放),那么第i+1行的值就可以根据第i行来求,即f[i+1][k]=∑f[i][j] (j&k==0表示这两行不会产生冲突)
例如第i行摆放状态为 00101,则第i+1行的状态10010满足条件.
最后我们得到状态转移方程
f[i][j]=∑f[i-1][k](k表示所有与j不冲突的状态,f[0][0]=1;
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
int s[1111]; /**记录所有满足条件的单行表示*/
long long f[11][1111];/**f[i][j]表示第i行为第j种状态的摆放总数*/
int n,m; /**n表示棋盘大小,m表示满足条件的状态数*/
long long ans; /**记录答案*/
bool ok(int x )/**判断x是否满足条件*/
{
while(x) /**将x不断右移,判断最右边两位是否都为1,都为1就是有冲突*/
{
if((x&3)==3)return 0;
x>>=1;
}
return 1;
}
int main()
{
int i,j,k;
while(~scanf("%d",&n))
{
for(m=i=0;i<1<<n;++i)
if(ok(i)) s[m++]=i; /**枚举所有摆放方案,并判断是否满足,满足就存储在s里*/
memset(f,0,sizeof(f)); /**赋初值*/
f[0][0]=1;
for(i=1;i<=n;++i) /**枚举每一行*/
for(j=0;j<m;++j) /**枚举第i行的状态*/
for(k=0;k<m;++k) /**枚举第i-1行的状态*/
if((j&k)==0)f[i][j]+=f[i-1][k]; /**如果不冲突就加上*/
ans=0;
for(i=0;i<m;++i)ans+=f[n][i]; /**统计答案*/
printf("%lld\n",ans); /**输出答案*/
}
return 0;
}