1087: [SCOI2005]互不侵犯King

1087: [SCOI2005]互不侵犯King

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 4276  Solved: 2471
[Submit][Status][Discuss]

Description

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

Input

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

Output

  方案数。

Sample Input

3 2

Sample Output

16

HINT

 

Source

/*
* @Author: LyuC
* @Date:   2017-09-03 21:24:43
* @Last Modified by:   LyuC
* @Last Modified time: 2017-09-04 21:55:56
*/

/*
 题意:在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
    左下右上右下八个方向上附近的各一个格子,共8个格子。
 
 思路:类似八皇后问题,k>n的情况方案数为0,然后剩下的搜索解决

 错误:这个和八皇后问题不一样,king只能攻击相邻一格,状压DP

 dp[i][j][k]表示第i行,j状态,已经按放k个棋子的状态

 状态转移:dp[i][j][cnt=从j状态中的棋子数枚举到需要放的总的棋子数]+=
    dp[i-1][上一行能满足下一行是j状态的状态][cnt-j状态的棋子数]

 总的来说动态规划就是抽象出来状态,就很简单了
*/
#include <bits/stdc++.h>

#define MAXN 15
#define MAXT 1024
#define MAXK 105
#define LL long long

using namespace std;

LL n,k;
LL dp[MAXN][MAXT][MAXK];//dp[i][j][k]表示第i行,第j种状态时,已经放下了k个棋子的方案数
LL tol;
LL cnt;
LL res;

bool ok(LL x,LL y){//判断上行的状态是否满足条件
    for(LL i=0;i<n;i++){
        if( (x&(1<<i)) ==0 ) continue;

        if(i==0){
            if( ( y&( 1<<i ) ) !=0 || ( y&( 1<<(i+1) ) ) !=0)
                return false;
        }else if(i==n-1){
            if( ( y&( 1<<i ) ) !=0 || ( y&( 1<<(i-1) ) ) !=0)
                return false;
        }else{
            if( ( y&( 1<<(i-1) ) ) !=0 || ( y&( 1<<(i+1) ) ) !=0 || ( y&( 1<<i ) ) !=0)
                return false;
        }
    }
    return true;
}

LL judge(LL x){//判断这个状态是不是合格的
    LL cur=0;
    for(LL i=0;i<n;i++){
        if( ( x&(1<<i) ) !=0){
            if(i==0){
                if( ( x&( 1<< (i+1) ) )!=0){
                    return -1;
                }
            }else if(i==n-1){
                if( ( x&(1<<(i+1)) )!=0 || ( x&(1<<(i-1)) )!=0 ){
                    return -1;
                }
            }else{
                if( ( x&(1<<(i-1)) )!=0){
                    return -1;
                }
            }
            cur++;
        }
    }
    return cur;
}

inline void init(){
    memset(dp,0,sizeof dp);  
    res=0;  
}

int main(){
    // freopen("in.txt","r",stdin);
    init();
    scanf("%lld%lld",&n,&k);

    tol=(1<<n);

    for(LL i=0;i<tol;i++){//初始化状态
        cnt=judge(i);
        if(cnt!=-1){
            dp[0][i][cnt]=1;
        }
    }

    for(LL i=1;i<n;i++){//从第二行开始递推状态
        for(LL j=0;j<tol;j++){//枚举当前行的状态
            cnt=judge(j);
            if(cnt==-1) continue;
            for(LL l=0;l<tol;l++){//枚举上一行的状态
                if(ok(j,l)==false) continue;
                for(LL d=cnt;d<=k;d++){
                    dp[i][j][d]+=dp[i-1][l][d-cnt];
                }
            }
        }
    }

    for(LL i=0;i<tol;i++){
        res+=dp[n-1][i][k];
    }
    printf("%lld\n",res);
    return 0;
}

 

posted @ 2017-09-04 21:59  勿忘初心0924  阅读(185)  评论(0编辑  收藏  举报