【bzoj1087】【scoi2005】互不侵犯King
题目描述
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子。
输入
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
输出
所得的方案数
样例输入
3 2
样例输出
16
题解
设dp[ i ][ j ][ k ] 表示第 i 行,状态为 j ,用了 k 个1的方案数。
转移需要枚举4个量: i 表示行数,k 第 i 行状态, j 第 i-1 行状态 ,tot 用了tot个1 。
#include<cmath> #include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define ll long long const int maxn=12; const int maxm=1<<maxn; int n,kk,state[maxm],top; ll ans,dp[maxn][maxm][maxn*maxn]; bool ok(int x){ if(x&(x<<1)) return false; return true; } void init(){ for(int i=0;i<(1<<n);i++) if(ok(i)) state[++top]=i; } bool fit(int x,int y){ if(state[x]&state[y]) return false; if(state[x]&(state[y]<<1)) return false; if(state[y]&(state[x]<<1)) return false; return true; } int count(int x){ int ret=0; while(x){ ret++; x&=x-1; } return ret; } template<typename T>void read(T& aa){ char cc; ll ff;aa=0;cc=getchar();ff=1; while((cc<'0'||cc>'9')&&cc!='-') cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int main(){ read(n),read(kk); init(); for(int i=1;i<=top;i++) dp[1][i][count(state[i])]=1; for(int i=2;i<=n;i++) for(int k=1;k<=top;k++){ int tot=count(state[k]); for(int j=1;j<=top;j++){ if(!fit(k,j)) continue; for(int l=tot;l<=kk;l++) dp[i][k][l]+=dp[i-1][j][l-tot]; } } for(int i=1;i<=top;i++) ans+=dp[n][i][kk]; cout<<ans<<endl; return 0; }