zoukankan      html  css  js  c++  java
  • 状压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;
    } 


  • 相关阅读:
    Vue日期转化
    javascript数组去重
    javascript数组及类数组详解
    javascript的argument和克隆方法详解
    javascript中对this的理解
    javascript命名空间及对象枚举的理解
    javascript继承模式详解
    javascript的call和apply区别
    javascript原型及原型链详解
    javascript对象及包装类
  • 原文地址:https://www.cnblogs.com/lipu123/p/13708789.html
Copyright © 2011-2022 走看看