数位DP模板题
link
题面
[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;
}