本文最后更新于:2024年9月13日 早上
题目描述
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
- 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
输入:
3 2
输出:
16
想法
状态压缩入门题目,洛谷的题单都这样吗?
感觉写状压的一个好处是只要思路对了,过了样例大概率就能A了(可能是目前做的题太水了)
就是正常的状压思路,hang[i][j][z]表示第i行状态为j已经有了z个国王可行的方案数,然后每一步递推时把上一行可以和谐共存的状态都加上即可。
思路没啥好说的,代码也加上了注释应该能看懂。
不过中间由于没有考虑状态压缩需要枚举的状态其实是0~maxn-1的,结果稍微多调了一会儿,需要记住。以及把行间判错封装成函数确实更方便了。以后或许可以考虑自己实现一些基础结构的封装作为模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| #include<bits/stdc++.h> using namespace std; long long n,k,d[20],Kingnum[10010],hang[15][610][101],maxn=1,sum=0; inline bool panduanhanghefa(int zhuangtai) { bool flag=true; for(int i=1;i<=n;i++) if(zhuangtai&d[i]) if((zhuangtai&d[i+1])||(zhuangtai&d[i-1])){flag=false;break;} return flag; } inline bool panduanliehefa(int zhuangtai1,int zhuangtai2) { bool flag=true; for(int i=1;i<=n;i++) if(zhuangtai1&d[i]) if((zhuangtai2&d[i])||(zhuangtai2&d[i+1])||(zhuangtai2&d[i-1])){flag=false;break;} return flag; }int aa[90]; inline void zhuangtaishuchu(int zhuangtai) { cout<<zhuangtai<<"&&"; for(int i=zhuangtai;i;i/=2)aa[++aa[0]]=i%2; for(int i=aa[0];i>=1;i--)cout<<aa[i];cout<<endl; aa[0]=0; } int main() { cin>>n>>k; for(int i=1;i<=n;i++)maxn*=2; d[1]=1;for(int i=2;i<=n;i++)d[i]=d[i-1]<<1; for(int i=0;i<maxn;i++)for(int j=i;j;j/=2)Kingnum[i]+=j%2; for(int i=0;i<maxn;i++) { if(!panduanhanghefa(i))continue; hang[1][i][Kingnum[i]]=1; } for(int i=2;i<=n;i++) { for(int j=0;j<maxn;j++) { if(!panduanhanghefa(j))continue; for(int j1=0;j1<maxn;j1++) { if(!panduanhanghefa(j1))continue; if(!panduanliehefa(j,j1))continue; for(int z=0;z<=k;z++) { if(z<Kingnum[j])continue; hang[i][j][z]+=hang[i-1][j1][z-Kingnum[j]]; } } } } for(int j=0;j<maxn;j++)sum+=hang[n][j][k]; cout<<sum<<endl; return 0; }
|