P1896 [SCOI2005] 互不侵犯
P1896 [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\)。
\(\text{upd 2018.4.25}\):数据有加强。
呃,没什么好说的直接上错误代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,k;
int dp[10][82][1<<9];
int num[1<<9];//每个状态的1的个数
int chse[1<<9];//每一行可选择的状态集合有哪些
int tot=0;
int add(int s){//s在二进制下的1的个数 int cnt=0;while(s){if(s&1) cnt++;s>>=1;}return cnt;
}
signed main(){cin>>n>>k;for(int i=0;i<(1<<n);i++){num[i]=add(i);if(i&(i<<1)==0&&i&(i>>1)==0){chse[++tot]=i;}}dp[0][0][0]=1;for(int i=1;i<=n;i++){for(int j=0;j<=k;j++){for(int x=1;x<=tot;x++){int s=chse[x];if(num[s]>j) continue; for(int y=1;y<=tot;y++){int t=chse[y];if(s&(t<<1)==0&&s&(t>>1)==0&&s&t==0){if(j-num[t]>=0){dp[i][j][t]+=dp[i-1][j-num[t]][s];}}} }}}int ans=0;for(int i=1;i<=tot;i++){ans+=dp[n][k][chse[i]];}cout<<ans;return 0;
}
让我们猜猜错误在哪
错在位运算优先级
正确代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,k;
int dp[10][82][1<<9];
int num[1<<9];//每个状态的1的个数
int chse[1<<9];//每一行可选择的状态集合有哪些
int tot=0;
int add(int s){//s在二进制下的1的个数 int cnt=0;while(s){if(s&1) cnt++;s>>=1;}return cnt;
}
signed main(){cin>>n>>k;for(int i=0;i<(1<<n);i++){num[i]=add(i);if((i&(i<<1))==0&&(i&(i>>1))==0){chse[++tot]=i;}}dp[0][0][0]=1;for(int i=1;i<=n;i++){for(int j=0;j<=k;j++){for(int x=1;x<=tot;x++){int s=chse[x];if(num[s]>j) continue; for(int y=1;y<=tot;y++){int t=chse[y];if((s&(t<<1))==0&&(s&(t>>1))==0&&(s&t)==0){if(j-num[t]>=0){dp[i][j][t]+=dp[i-1][j-num[t]][s];}}} }}}int ans=0;for(int i=1;i<=tot;i++){ans+=dp[n][k][chse[i]];}cout<<ans;return 0;
}
关于两个初始化
我认为的初始化
for(int i=0;i<=n;i++){for(int t=0;t<(1<<n);t++){dp[i][0][t]=1;}}
正确的初始化
dp[0][0][0]=1;
那么为什么我的初始化会错呢?
在计数dp下,注意答案会被重复计算