棋子--状态压缩dp

题目描述:在一个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;
}



你可能感兴趣的:(棋子--状态压缩dp)