bzoj1087 互不侵犯King 状压dp+bitset
题目大意:中文题面。
思路:又是格子,n又只有9,所以肯定是状压dp,很明显上面一行的摆放位置会影响下一行,所以先预处理出怎样的二进制摆放法可以放在上下相邻的两行,这里推荐使用bitset,否则会比较麻烦。然后dp的数组是f[ i ][ x ][ j ],表示第i行已经放置了x个国王,第 i 行的状态是 j 。同时预处理出对于每一种二进制位,可以增加几个国王,计做cnt[ j ],所以得到 if(mp[ s ][ j ]) f[ i +1 ][x +cnt[ j ]][ j ]+=f[ i ][ x ][ s ].
#include<bits/stdc++.h> #define CLR(a,b) memset(a,b,sizeof(a)) using namespace std; typedef long long ll; bitset<10>a,b; int mp[600][600]; ll cnt[600]; ll f[10][200][600]; int n,k; inline void init() {//预处理出怎样的两行可以放在一起 for(int i=0; i<(1<<9); i++) { for(int j=0; j<(1<<9); j++) { a=i,b=j; bool f=1; if(a[0]==true) { if(a[1]||b[0]||b[1])f=0; } if(a[8]==true) { if(a[7]||b[7]||b[8])f=0; } for(int x=1; x<9-1; x++) { if(a[x]==true) { if(a[x-1]||a[x+1]||b[x-1]||b[x]||b[x+1]) { f=0; break; } } } if(f) { mp[i][j]=1; } } } for(int i=0; i<(1<<9); i++) { b=i; for(int j=0; j<9; j++) { if(b[j])cnt[i]++; } for(int j=0; j<(1<<9); j++) { mp[i][j]=mp[i][j]&mp[j][i]; mp[j][i]=mp[i][j]&mp[j][i]; } } } int main() { cin>>n>>k; init(); for(int i=0; i<(1<<n); i++) { if(mp[0][i]) { f[1][cnt[i]][i]=1; } } for(int i=1; i<n; i++) { for(int j=0; j<(1<<n); j++) { for(int d=0; d<(1<<n); d++) { if(mp[j][d]) { for(int x=0; x<=k; x++) { f[i+1][x+cnt[d]][d]+=f[i][x][j]; } } } } } ll ans=0; for(int i=0;i<(1<<n);i++){ ans+=f[n][k][i]; } cout<<ans<<endl; }
1087: [SCOI2005]互不侵犯King
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 6076 Solved: 3570
[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
——愿为泰山而不骄
qq850874665~~