1. 程式人生 > 其它 >P1896 [SCOI2005]互不侵犯

P1896 [SCOI2005]互不侵犯

[SCOI2005]互不侵犯

題目描述

在N×N的棋盤裡面放K個國王,使他們互不攻擊,共有多少種擺放方案。國王能攻擊到它上下左右,以及左上左下右上右下八個方向上附近的各一個格子,共8個格子。 注:資料有加強(2018/4/25)

輸入輸出格式

輸入格式

只有一行,包含兩個數N,K ( 1 <=N <=9, 0 <= K <= N \* N)

輸出格式

所得的方案數

輸入輸出樣例

輸入樣例 #1

3 2

輸出樣例 #1

16

狀壓模板題


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;

int n, k;

const int N = 12;

long long f[N][N * N][1 << N];
vector  state, head[1 << N];

int cnt[1 << N];

bool check(int state)
{
    for(int i = 0 ; i < n; i++)
    {
        if((state >> i & 1 ) && (state >> i + 1 & 1))
        {
            return 0;
        }
    }
    return 1;
}


int count(int state)
{
    int res = 0 ;
    for(int i = 0 ; i < n; i++)
        res += state >> i & 1;
    return res;
}

int main()
{
    scanf("%d %d", &n, &k);
    for(int i = 0; i < 1 << n; i++)
    {
        if(check(i)) 
        {
            state.push_back(i);
            cnt[i] = count(i);
        }
        
    }
     for (int i = 0; i < state.size(); i ++ )
        for (int j = 0; j < state.size(); j ++ )
        {
            int a = state[i], b = state[j];
            if ((a & b) == 0 && check(a | b))
                head[i].push_back(j);
        }
    
    f[0][0][0] = 1;
    for(int i = 1; i <= n + 1; i++)
    {
        for(int j = 0 ; j <= k; j++)
        {
            for(int a = 0 ;a < state.size(); a++)
            {
                for(int p = 0 ; p < head[a].size(); p++)
                {
                    int b = head[a][p];
                    int c = cnt[state[a]];
                    if(j >= c)
                    {
                        f[i][j][a] += f[i - 1][j - c][b];
                    }
                }
            }
        }
    }
    printf("%lld", f[n + 1][k][0]);
    return 0;
    
}