Evanyou Blog 彩带

P1896 [SCOI2005]互不侵犯

题目描述

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

注:数据有加强(2018/4/25)

输入输出格式

输入格式:

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

输出格式:

所得的方案数

输入输出样例

输入样例#1: 
3 2
输出样例#1: 
16

 

Solution:

  本题状压dp水题

  预处理单行合法的状态和所放国王数,定义$f[i][j][k]$表示前$i$行放了$j$个国王且最后一行状态为$k$时的方案数。

  那么转移就比较简单了,一层枚举阶段j(国王数),第二层枚举阶段i(行数),第三层枚举状态k(最后一行国王状态),第四层枚举决策p(转移后状态),判断合法后随便搞搞就好了。

代码:

/*Code by 520 -- 10.14*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=10;
int n,m,lim,w[1<<N];
ll f[N][N*N*2][1<<N],ans;
bool sta[1<<N];

int main(){
    ios::sync_with_stdio(0);
    cin>>n>>m,lim=(1<<n)-1;
    For(i,0,lim) {
        sta[i]=(!(i&(i<<1))&&!(i&(i>>1)));
        if(sta[i])
            For(j,0,n-1) if(i&(1<<j)) w[i]++;
    }
    f[0][0][0]=1;
    For(p,0,m) For(i,1,n) For(j,0,lim)
        if(sta[j]) For(k,0,lim) 
            if(sta[k]&&!(j&k)&&!((j<<1)&k)&&!((j>>1)&k))
                f[i][p+w[j]][j]+=f[i-1][p][k];
    For(i,0,lim) ans+=f[n][m][i];
    cout<<ans;
    return 0;
}

 

posted @ 2018-10-25 20:44  five20  阅读(149)  评论(0编辑  收藏  举报
Live2D