状压dp(洛谷:互不侵犯)

洛谷:P1896

视频题解:

在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子

输入格式

只有一行,包含两个数N,K ( 1 <=N <=9, 0 <= K <= N * N)

输出格式

所得的方案数

输入输出样例

输入 #1
3 2
输出 #
16


f[i][st][j]代表的是前i行第j列的二进制数是st且有j个棋子的方案数
f[i][st][j]=Σf[i-1][st2][j-c(st2)]
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
template <typename Tp>
void read(Tp &x){//read(n);
    x=0;char ch=1;int fh;
    while(ch!='-'&&(ch>'9'||ch<'0')){
        ch=getchar();
    }
    if(ch=='-'){
        fh=-1;ch=getchar();
    }else fh=1;
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+ch-'0';ch=getchar();
    }
    x*=fh;
}
inline char read1()//字符串读入挂
{
    register char ch=getchar();
    while(ch<'A'||ch>'M')ch=getchar();
    return ch;
}
const int maxn=1e6+100;
int n,k;
ll f[9][1<<9][100],ans;
int c(int st){//返回st的二进制表示中存了多少位1 
    int cnt=0;
    while(st){
        if(st%2){
            cnt++;
        }
        st/=2;
    }
    return cnt;
}
bool check1(int st){//判断单行状态st是否合法 
    for(int i=0;i+1<n;i++){
        if((st & (1<<i)) && (st & (1<<(i+1)))) return false;
    }
    return true;
}
bool check2(int st,int st2){//判断当前行st和他的上一行状态st2之间的关系是否合法 
    for(int i=0;i<n;i++){
        if(st & (1<<i)){
            if(st2 & (1<<i)){
                return false;
            }
            else if(i+1 < n && (st2 & (1<<(i+1)))){
                return false;
            }
            else if(i-1 < n && (st2 & (1<<(i-1)))){
                return false;
            }
        }
    }
    return true;
}
int main(){
    cin>>n>>k;
    for(int i=0;i<n;i++){
        for(int st=0;st < (1<<n);st++){
            if(!check1(st)) continue;
            if(i==0) f[i][st][c(st)] = 1;
            else{
                for(int j=c(st);j<=k;j++){
                    for(int st2=0;st2 < (1<<n);st2++){
                        if(!check1(st2)||!check2(st,st2)) continue;
                        f[i][st][j]+=f[i-1][st2][j-c(st)];
                    }    
                }
            }
        }
    }
    for(int st = 0;st < (1<<n); st++){
        ans += f[n-1][st][k];
    }
    cout<<ans<<endl;
} 

 



posted @ 2020-09-21 21:32  lipu123  阅读(148)  评论(0编辑  收藏  举报