//

[题解]P1896互不侵犯

数位DP模板题

题面

[SCOI2005] 互不侵犯

题目描述

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

输入格式

只有一行,包含两个数 \(N,K\)

输出格式

所得的方案数

样例 #1

样例输入 #1

3 2

样例输出 #1

16

提示

数据范围及约定

对于全部数据,\(1 \le N \le 9\)\(0 \le K \le N\times N\)


思路

设置 dp[i][j][k]表示第 \(i\) 排 状态用二进制表示为 \(j\),前 \(i\) 排一共放了 \(k\) 个棋子的方案数。

转移方程为:

\[dp[i][j][k] = \sum_{j_1} dp[i-1][j_1][k-j] \]

其中 \(j_1\) 表示上一行的状态,\(k_j\) 表示上一行放了多少个棋子。

注意:\(j\)\(j_1\) 不能有相邻的 \(1\)

时间复杂度为 \(O(n^2k^2)\),可以通过。

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,K;
int dp[10][(1<<10)][90];
signed main(){
    cin >> n >> K;
    dp[0][0][0]=1;
    for(int k=1;k<=n;k++){
        for(int i=0;i<(1<<n);i++){
            for(int j=0;j<(1<<n);j++){
                for(int p=0;p<=K;p++) {
                    if((i&j)|(j<<1&i)|(j>>1&i)|(i<<1&i)) continue;
                    dp[k][i][p+__builtin_popcount(i)]+=dp[k-1][j][p];
                }
            }
        }
    }
    int ans=0;
    for(int i=0;i<(1<<n);i++){
        ans+=dp[n][i][K];
    }
    cout << ans;
    return 0;
}

其他数位DP题目

炮兵阵地

Corn Fields G

邦邦的大合唱站队

posted @ 2024-07-18 16:31  Gao_l  阅读(61)  评论(0)    收藏  举报