zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    牛客(14)链表中倒数第k个结点
    牛客(13)调整数组顺序使奇数位于偶数前面
    牛客(12)数值的整数次方
    牛客(11)二进制中1的个数
    牛客(10)矩形覆盖
    牛客(9)变态跳台阶
    牛客(8)跳台阶
    牛客(7)斐波那契数列
    Docker数据卷
    Docker镜像
  • 原文地址:https://www.cnblogs.com/mountaink/p/9977030.html
Copyright © 2011-2022 走看看