1087: [SCOI2005]互不侵犯King
Description
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。
Input
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
Output
方案数。
Sample Input
3 2
Sample Output
16
状压DP。。。
f[i][j][k]表示前j-1行选了i个人,第j行状态为k时的方案总数。。。
所以状态转移方程就是f[i+sum][j][k]+=f[i][j-1][l] sum是状态k中放的棋子数。。
1 #include<iostream> 2 #include<cstdlib> 3 #include<cmath> 4 #include<cstring> 5 #include<cstdio> 6 #include<algorithm> 7 #include<string> 8 #include<map> 9 #include<queue> 10 #include<vector> 11 #include<set> 12 #define inf 1000000000 13 #define maxn 10000+5 14 #define maxm 10000+5 15 #define eps 1e-10 16 #define ll long long 17 #define for0(i,n) for(int i=0;i<=(n);i++) 18 #define for1(i,n) for(int i=1;i<=(n);i++) 19 #define for2(i,x,y) for(int i=(x);i<=(y);i++) 20 #define for3(i,x,y) for(int i=(x);i>=(y);i--) 21 #define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go) 22 using namespace std; 23 int read(){ 24 int x=0,f=1;char ch=getchar(); 25 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 26 while(ch>='0'&&ch<='9'){x=10*x+ch-'0';ch=getchar();} 27 return x*f; 28 } 29 ll f[100][10][600]; 30 int n,m,a[maxn]; 31 int main(){ 32 //freopen("input.txt","r",stdin); 33 //freopen("output.txt","w",stdout); 34 memset(f,0,sizeof(f)); 35 n=read();m=read();a[1]=1; 36 for(int i=2;i<=10;i++) 37 a[i]=a[i-1]<<1; 38 f[0][0][0]=1; 39 for1(j,n) 40 for0(i,m) 41 for0(k,a[n+1]-1){ 42 if((k>>1&k)||(k<<1&k))continue; 43 int tmp=k,tot=0; 44 while(tmp){ 45 tot+=tmp&1;tmp>>=1; 46 } 47 if(tot>i)continue; 48 for0(l,a[n+1]-1){ 49 if((l>>1&l)||(l<<1&l))continue; 50 if((l&k)||(l<<1&k)||(l>>1&k))continue; 51 int tmp2=l,tot2=0; 52 while(tmp2){ 53 tot2+=tmp2&1;tmp2>>=1; 54 } 55 if(tot2>m-i)continue; 56 f[i+tot2][j][l]+=f[i][j-1][k]; 57 } 58 } 59 ll ans=0; 60 for0(i,a[n+1]-1) 61 ans+=f[m][n][i]; 62 printf("%lld\n",ans); 63 return 0; 64 }