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 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

原文地址:https://www.cnblogs.com/mountaink/p/9977030.html

时间: 2024-11-05 16:40:15

bzoj1087 互不侵犯King 状压dp+bitset的相关文章

[BZOJ1087] [SCOI2005] 互不侵犯King (状压dp)

Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. Input 只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N) Output 方案数. Sample Input 3 2 Sample Output 16 HINT Source Solution 状压$dp$就是把状态压缩成二进制数,利用二进制的位运算改进算法的一种方法

【BZOJ1087】 [SCOI2005]互不侵犯King 状压DP

经典状压DP. f[i][j][k]=sum(f[i-1][j-cnt[k]][k]); cnt[i]放置情况为i时的国王数量 前I行放置情况为k时国王数量为J 1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 #define N 1<<9 5 long long ans; 6 int n,m; 7 int ok_1[N],cnt[N]; 8 int ok_2[N][N]; 9 long

BZOJ 1087: [SCOI2005]互不侵犯King( 状压dp )

简单的状压dp... dp( x , h , s ) 表示当前第 x 行 , 用了 h 个 king , 当前行的状态为 s . 考虑转移 : dp( x , h , s ) = ∑ dp( x - 1 , h - cnt_1( s ) , s' ) ( s and s' 两行不冲突 , cnt_1( s ) 表示 s 状态用了多少个 king ) 我有各种预处理所以 code 的方程和这有点不一样 ------------------------------------------------

BZOJ 1087 SCOI 2005 互不侵犯King 状压DP

题目大意:一个国王可以攻击到旁边8个位置的格子,现在给出一个N*N的方格,向其中放k个国王,问有多少中摆放方法. 思路:状压DP,f[i][j][k],其中i是行数,j是状态,k是已经取了多少国王.然后暴力枚举状态,看相邻两行之间有没有冲突,若没有冲突,那么就转移. 注意要开long long CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm>

【题解】[SCOI2005] 互不侵犯 (状压DP)

[SCOI2005] 互不侵犯 终于懂一点状压DP了… 用一个数的二进制形式表示一整行的状态,比如 18(1010)表示第一列和第三列有国王. 然后用&判断是否可行: if((x&y)||((x<<1)&y)||(x&(y<<1))) continue;1code: #include<iostream>#include<cstdio>#include<cstring>#include<algorithm>

[SCOI2005]互不侵犯(状压Dp)

题目 原题 Solution 看到数据范围就可以想到状压,然后你就可以直接转移就好了? #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<iostream> #include<queue> #include<algorithm> #define ll long long #define file(a) freo

bzoj1087互不侵犯King(状压)

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1087 简单的状压dp.但是wa了好几发.注意long long. 注意0和0的连边.而且不能连成两条,所以放在外面写. #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=15,M=1<<9; int n,m,lm,list[M+5

codevs 2451 互不侵犯(状丫dp)

/* 好神奇好神奇...表示自己要学的还很多 注意到n<=9 不是搜索就是状丫 搜索+剪枝 70分 枚举放或者不放 这里用状丫 f[i][j][k] 表示前i行 放了j个国王 i行的状态是k的方案数 转移的话 枚举下层的状态 算出这个状态中有几个国王 然后更新 复杂度 2^n*2^n*n*K*n 最后一个n是算国王数 这个可以预处理搞出来 还有一个问题就是 互相伤害的问题 首先在同一行里 相邻的不行 不同行的就左移右移一下就好了 顺带处理好两个状态能不能互相转移 最后Σf[n][K][i] */

【一天一DP计划】状压DP

##P1896 互不侵犯[状压dp] 用01串表示每一行的可行解 列与列之间的限制条件在转移的时候continue x&=(-x)可以找到x的二进制位上有多少个1 关于位运算的优先级!不确定就无脑加括号哦哦 reference: https://www.luogu.org/blog/virus2017/1896dnqec Date: 2019.10.04 */ #include<bits/stdc++.h> using namespace std; #define int long l