AcWing1064.骑士(状压DP)题解

Acwing.骑士(状压DP)

题目传送门

题目描述

在 n×n 的棋盘上放 k 个国王,国王可攻击相邻的 8 个格子,求使它们无法互相攻击的方案总数。

输入格式

共一行,包含两个整数 n 和 k。

输出格式

共一行,表示方案总数,若不能够放置则输出00。

数据范围

1 ≤ n ≤ 10
0 ≤ k ≤ n^2

输入样例:

3 2

输出样例:

16

题解:

状态压缩DP:

dp[ i ] [ j ] [ k ]表示第 i 行,状态为 j , 放国王的个数为k时的方案数
其中j用二进制表示, 1表示该位置上放国王,0表示该位置上不放国王

#include<iostream>
using namespace std;
const int N = 12;
typedef long long ll;
ll d[12][1 << N][110];
int n, m;
int num[1 << N], temp[1 << N];
int get_ones(int x)
{
    int cnt = 0;
    while(x){
        if(x & 1)cnt++;
        x >>= 1;
    }
    return cnt;
}
int main()
{
    cin >> n >> m;
    int t = 0;
    for(int i = 0; i < 1 << n; i++){  //预处理出每一行的n种状态, 1表示放了国王,0表示没有放国王
        if(i & (i << 1))continue; //相邻俩个不能同为1
        temp[t] = i;  //记录该状态
        num[t++] = get_ones(i);  //记录该状态下国王的个数
    }
    d[0][0][0] = 1;
    for(int i = 1; i <= n; i++){   //枚举每一行
        for(int j = 0; j < t; j++){  //枚举改行的所有状态
            for(int k = 0; k < t; k++){ //枚举前一行所有的状态

                //同一列上的不能全为1, 且对角不能都是1
                if(temp[j] & temp[k] || (temp[j] >> 1 & temp[k] || temp[j] << 1 & temp[k]))continue;
                //枚举第i - 1行放国王的个数
                for(int r = 0; r + num[j] <= m; r++){
                    d[i][j][r + num[j]] += d[i - 1][k][r];
                }
            }
        }
    }
    ll ans = 0;
    for(int i = 0; i < t; i++)  //输出所有状态的总和
        ans += d[n][i][m];
    cout << ans << endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43328040/article/details/106834882