1087: [SCOI2005]互不侵犯King
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3235 Solved: 1878
[ Submit][ Status][ Discuss]
Description
在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上
左下右上右下八个方向上附近的各一个格子,共8个格子。
Input
只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)
Output
方案数。
Sample Input
3 2
Sample Output
16
状压国王的摆放方案,预处理方案是否合法,
强行看错题...
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
long long dp[10][100][1000];
int n,k,hf[1<<10],kings[1<<10],htop;
int sum(int x){
int ans=0;
while(x>0)x-=x&-x,ans++;
return ans;
}
bool check(int x,int y){
return (hf[x]&hf[y])||((hf[x]<<1)&hf[y])||((hf[x]>>1)&hf[y]);
}
int main(){
scanf("%d%d",&n,&k);
if(n==1){
printf("1");
return 0;
}
for(int i=0;i<(1<<n);++i){
for(int j=0;j<n;++j)if((i>>j)&1){
if(j>0&&((i>>j-1)&1))goto end;
else if(j<n-1&&((i>>j+1)&1))goto end;
}
hf[++htop]=i;
end:;
}
for(int i=1;i<=htop;++i)kings[i]=sum(hf[i]);
dp[0][0][1]=1;
for(int i=0;i<n;++i)for(int j=0;j<=k;++j)
for(int s=1;s<=htop;++s)if(dp[i][j][s]){
// dp[i+1][j][1]+=dp[i][j][s];
for(int w=1;w<=htop;++w)if(!check(s,w))
if(kings[w]+j<=k)dp[i+1][j+kings[w]][w]+=dp[i][j][s];
}
long long ans=0;
for(int s=1;s<=htop;++s)ans+=dp[n][k][s];
printf("%lld",ans);
}