• luogu P1896 [SCOI2005]互不侵犯King


    题目描述

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

    输入输出格式

    输入格式:

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

    输出格式:

    所得的方案数

    输入输出样例

    输入样例#1:
    3 2
    
    输出样例#1:
    16
    题目链接:https://daniu.luogu.org/problem/show?pid=1896.
    解题报告
    状压DP经典好题
    将放不放king的0/1状态压成一个数.
    首先我们要学会一些高端操作:
    (1)i&(i>>1)可以判断当前状态i是否合法,
    若i&(i>>1)==0表示状态i中没有相邻的king,为合法方案.
    若i&(i>>1)!=0表示状态i中有相邻的king,为非法方案.
    For example:
    [1].i=(1010101)2,i>>1=(101010)2,i&(i>>1)=(0)2.为合法方案.
    [2].i=(1000111)2,i>>1=(100011)2,i&(i>>1)=(11)2.为非法方案.
    (2)若有相邻两行状态i和j,
    那么满足i&j==0&&(i<<1)&j==0&&(i>>1)&j==0,则相邻两行状态合法,否则为非法方案.
    For example:
    [1].i=(100010001)
    2,j=(001000100)2,
    i&j=(0)2,(i<<1)&j=(0)2,(i>>1)&j=(0)2.为合法方案.
    [2].i=(101010101)2,j=(010101010)2,i&j=(0)2,(i<<1)&j=(10101010)2,(i>>1)&j=(10101010)2.为非法方案.
    以上均为O(1)复杂度的判断.
    进入正题:
    先枚举合法状态i中king的个数,记录到num[i]中.再定义状态转移方程f[i][j][k],表示1~i行用了j个数且第i的状态为k的方案数.
    初始化f[0][0][0]=1.先枚举行数i,复杂度O(n).再枚举king的个数,复杂度O(m).接着第i行的状态k,复杂度O(2n).最后枚举i-1行的状态k,复杂度为O(2n).
    判断是否满足条件,进行转移f[i][j][k]=f[i][j][k]+f[i-1][j-num[k]][l].总复杂度为O(n*m*22n).最后,ans=∑(i=0,2n-1)f[n][m][i].
    #include<cstdio>
    #include<iostream> 
    #define ll long long
    #define FOR(i,s,t) for(register int i=s;i<=t;++i)
    using namespace std;
    int num[1025],T;
    ll f[10][121][1025];
    int n,m;
    ll ans;
    int main(){
        scanf("%d%d",&n,&m);
        T=(1<<n)-1;
        FOR(i,0,T)
            for(register int k=i;k;k>>=1)
                if(k&1)
                    ++num[i];
        f[0][0][0]=1ll;
        FOR(i,1,n)
            FOR(j,0,m)
                FOR(k,0,T)
                    if(!((k<<1)&k)&&!((k>>1)&k)&&j>=num[k])
                        FOR(l,0,T)
                            if(!((l<<1)&l)&&!((l>>1)&l)&&!(l&k)&&!((k<<1)&l)&&!((k>>1)&l))
                                f[i][j][k]=(ll)(f[i][j][k]+f[i-1][j-num[k]][l]);
        FOR(k,0,T)
            ans=(ll)(ans+f[n][m][k]);
        cout<<ans<<endl; 
        return 0;
    }
    
    
    

      

     
    
    
    

  • 相关阅读:
    从gettext来看linux下程序的internationalization
    C++ Convert Operator和其他Operator的应用场景比较
    申明一个函数指针,并且该函数的返回值也是一个函数指针 示例代码
    XML操作大全
    如何让页面延迟显示?
    Ajax实现不刷屏的前提下实现页面定时刷新
    我喜欢的笑话 呵呵
    Atlas UpdatePanel使用技巧以及常见问题
    asp.net 弹出窗体
    C# asp.net操作文件
  • 原文地址:https://www.cnblogs.com/Stump/p/7684397.html
Copyright © 2020-2023  润新知