P1896 [SCOI2005]互不侵犯
题目描述
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
注:数据有加强(2018/4/25)
输入输出格式
输入格式:只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
输出格式:所得的方案数
输入输出样例
输入样例#1:
3 2
输出样例#1:
16
Solution:
本题状压dp水题。
预处理单行合法的状态和所放国王数,定义$f[i][j][k]$表示前$i$行放了$j$个国王且最后一行状态为$k$时的方案数。
那么转移就比较简单了,一层枚举阶段j(国王数),第二层枚举阶段i(行数),第三层枚举状态k(最后一行国王状态),第四层枚举决策p(转移后状态),判断合法后随便搞搞就好了。
代码:
/*Code by 520 -- 10.14*/ #include<bits/stdc++.h> #define il inline #define ll long long #define RE register #define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++) #define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--) using namespace std; const int N=10; int n,m,lim,w[1<<N]; ll f[N][N*N*2][1<<N],ans; bool sta[1<<N]; int main(){ ios::sync_with_stdio(0); cin>>n>>m,lim=(1<<n)-1; For(i,0,lim) { sta[i]=(!(i&(i<<1))&&!(i&(i>>1))); if(sta[i]) For(j,0,n-1) if(i&(1<<j)) w[i]++; } f[0][0][0]=1; For(p,0,m) For(i,1,n) For(j,0,lim) if(sta[j]) For(k,0,lim) if(sta[k]&&!(j&k)&&!((j<<1)&k)&&!((j>>1)&k)) f[i][p+w[j]][j]+=f[i-1][p][k]; For(i,0,lim) ans+=f[n][m][i]; cout<<ans; return 0; }
PS:~蒟蒻写博客不易,转载请注明出处,万分感谢!~