zoukankan      html  css  js  c++  java
  • SCOI2005 互不侵犯

    传送门

    这道题看数据范围<=9,很容易想到是状压DP。

    根据各位dalao的讲述,状压DP中经常把每一个行的情况都压缩起来,之后进行DP。那么这样的话想起DP的状态就比较简单,dp[i][j][s]表示枚举到第i行,第i行的状态为j,算上当前行一共放了s个国王一共有多少种情况。其中j是一个二进制串,某一位是1代表该位有国王,否则没有。

    那么dp方程就是: dp[i][j][s] = sum{dp[i-1][k][s-num[j]]},其中k是上一行能取到的状态,num指的是本行这种状态(j)中一共有几个国王。其中i,j,k,s都是枚举的。

    不过算来直接枚举会超时……思考一下,因为国王是互不侵犯的,所以对于每一行来说,肯定有很多种状态是根本不可选择的。那我们先预处理出所有可能存在的情况再去枚举。方法很简单,对于状态i,如果i&(i<<1),那么就说明当前的状态是不可选择的。直接排除掉即可。

    之后,对于每两行的情况,我们仿照上面的做法&一下即可。比如当前两行的状态为x,y,如果x&y || x&(y<<1)|| (x<<1 )& y说明这两种状态之间是不可转移的(因为会互相侵犯)

    这样进行转移就可以了,注意要预处理第一行的所有情况。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    
    using namespace std;
    const int M = 10;
    typedef long long ll;
    
    ll read()
    {
        ll ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-') op = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            ans *= 10;
            ans += ch - '0';
            ch = getchar();
        }
        return ans * op;
    }
    ll n,k,dp[M][1<<M][M<<2],gk[1<<M],ans,cnt,num[1<<(M+1)];
    
    ll getsum(ll x)
    {
        ll cur = 0;
        while(x) cur += (x&1),x >>= 1;
        return num[cnt] = cur;
    }
    int main()
    {
        n = read(),k = read();
        rep(i,0,(1<<n)-1) if(!(i&(i<<1))) gk[++cnt] = i,dp[1][cnt][getsum(i)] = 1;//第一行的预处理,同时处理出所有可行状态
        rep(i,2,n)
        rep(j,1,cnt)
        {
            ll x = gk[j];
            rep(p,1,cnt)
            {
                ll y = gk[p];
                if((x & y) || (x & (y << 1)) || ((x << 1) & y)) continue;//排除不可转移的情况
                rep(q,0,k) if(q >= num[j]) dp[i][j][q] += dp[i-1][p][q-num[j]];//把可行的情况加上即可
            }
        }
        rep(i,1,cnt) ans += dp[n][i][k];
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    __name__使用方法,模块查找顺序和模块的绝对导入
    模块
    ATM程序结构
    迭代器
    常用内置方法
    生成式,匿名函数及内置函数部分使用方法
    算法之二分法和三元表达式
    redis配置文件
    PythonStudy——shutil 模块
    PythonStudy——pickle 模块 (泡菜)
  • 原文地址:https://www.cnblogs.com/captain1/p/9557370.html
Copyright © 2011-2022 走看看