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;
}
View Code

1087: [SCOI2005]互不侵犯King

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 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
posted @ 2018-11-18 09:29  光芒万丈小太阳  阅读(185)  评论(0编辑  收藏  举报