【bzoj1087】互不侵犯King

Description

  在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。

Input

  只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

Output

  方案数。

Sample Input

  3 2

Sample Output

  16
 

Solution

我们很容易的联想到状态压缩动态规划

 

f[i][j][k][S]表示当前做到(i,j)这个格子共放了k个国王红色部分状态为S的方案数
然后只要枚举当前格子放不放的问题了
红色部分使用状态压缩,而红色部分之前的东西已经不影响答案了
当然可以使用滚动数组
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<queue>
#include<map>
#include<vector>
#include<set>
#define il inline
#define re register
using namespace std;
typedef long long ll;
int s=0,t=1,n,m;
ll f[2][101][1111],ans=0;
il bool chk(int j,int S){
     if(j==n) return (S&1)==0&&(S&2)==0&&(S&(1<<n))==0;
     else if(j==1) return (S&2)==0&&(S&4)==0;
     return (S&1)==0&&(S&2)==0&&(S&(1<<n))==0&&(S&4)==0;
}
int main(){
    scanf("%d%d",&n,&m); 
    if(n==1){
        cout<<"1";exit(0);
    }
    if(n==2){
        if(m==0) cout<<"1";
        else if(m==1) cout<<"4";
        else cout<<"0";
        exit(0);
    }
    f[0][0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            memset(f[t],false,sizeof(f[t]));
            for(int S=0;S<(1<<n+1);S++){
                for(int l=0;l<=m;l++){
                    if(chk(j,S)) f[t][l+1][(S>>1)|(1<<n)]+=f[s][l][S];
                    f[t][l][S>>1]+=f[s][l][S];
                }
            }
            swap(s,t);
        }
    }
    for(int S=0;S<(1<<n+1);S++) ans+=f[s][m][S];
    cout<<ans;
    return 0;
}

 

 
posted @ 2016-11-20 18:59  ExiledPoet  阅读(305)  评论(0编辑  收藏  举报