zoukankan      html  css  js  c++  java
  • 状态压缩与二进制

    自己最烦二进制,但还是痛定思痛,耐心学着...

    普通的数都是十进制,二进制便是逢2进一,我觉得它最大的用途就可以表示一系列的东西用于不用上,用则为1,不用为0,比如说四个物体,可以用1111表示,再把1111用十进制表示15,这样15就可以表示这一状态。

    说从最基础的说起:一般的n个物体,用二进制表示就需要有n个位置,这时的十进制是多少呢?可以用<<表示,例如1<<2,就表示100,那n个物体就需要1<<n,才能表示1后n个0,前面要多一个1,因为你要把n个1的情况也包括,例如:n=4,1<<4就表示10000,开数组后从0计数,就可以包括1111这种状态了,其实不难发现,1<<n和2的n次方是一样的.所以数据范围一般就是2的n次方倍时就可以考虑状压了。

    其次:要明白一些最基本的位运算的用法:&表示与,有0取0,|表示或,有1取1,^表示异或,相同取0,否则取1.这个对我来说挺难记得,我是这样记得:&,|,^,这三个顺序记好,之后就是0,1,是否相等...还有就是<<=就是数要向左移几位,后面用0补齐,例如:4<<2,4用二进制表示为100,操作后变成10000;相反>>=就是原数想右移,最后几位舍去,例如:4>>2就从100变成了1;

    说一些其他用法,基本上是状压DP需要的:如何判断一个二进制数的某一位是否为1或0呢?可以用&,|与1的左移,例如:if(i&1<<(j-1)) continue;表明如果i的二进制数如果第j位为1的话,就跳过;其实很好理解,1<<(j-1)就表示一个第j位为1,其余位为0的二进制数。此事用i与它做&运算,有0取0,所以除了第j位,其余位一定取0,那么如果第j位为0,整体就是0,不执行.相反,如果第j位为1,整体有值,进行continue。如果想要判断为0是跳过,只需在前面加上!即可.之后再说如何修改?即例如1011,如何改成1111,把0改成另一个状态.这时我们就要用上|,也就是有1取1,例如:i|1<<(j-1)(此时已判断过i的第j位为0)就表示i的第j位由0变成1.这个很好理解由于1<<(j-1)除了第j位上为1,其余位上都是0,此时的|相当于把i的其他位复制下来,只把第j位修改为1;

    好了说了这么多见题:

    此题我第一次看就想不到DP,因为它是排列型的问题.不知道该怎么用状态表示,之后才明白这时状压DP的例题...

    既然是排列,那我们就只能标记用于不用,用用过的推没用过的...

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define _ 0
    using namespace std;
    const int maxn=20;
    ll f[1<<maxn][maxn],n,H,h[maxn],ans;
    int main()
    {
        freopen("1.in","r",stdin);
        cin>>n>>H;
        for(int i=1;i<=n;i++) cin>>h[i];
        for(int i=1;i<=n;i++) f[1<<(i-1)][i]=1; //对第i位只放i的初始化;
        for(int i=1;i<=(1<<n)-1;i++)
            for(int j=1;j<=n;j++) //枚举上一个 
                for(int k=1;k<=n;k++) //枚举当前放的
                {
                    if(i&1<<(k-1)) continue; //假如说当前k已经放过则跳过.
                    if(abs(h[k]-h[j])>H) f[i|1<<(k-1)][k]+=f[i][j];
                }
        for(int i=1;i<=n;i++) ans+=f[(1<<n)-1][i];
        cout<<ans<<endl;
        return (0^_^0);         
    }

    好了,就到这吧!

  • 相关阅读:
    理解BSTR数据类型 神奇的BSTR
    char *
    _variant_t和_bstr_t
    数据库中创建表(包括创建主键,外键,非空列,唯一)
    使用ADO实现BLOB数据的存取 -- ADO开发实践之二
    sql server 2005 修改动态端口,连接字符串为:需要改成:IP地址+逗号+端口号才行
    Bilateral Filtering(双边滤波) for SSAO
    关于在Arduino中调用DS1302模块
    关于电机驱动扩展板 L293D 马达板Arduino
    Arduino教程资料汇总(8月22日悄悄跟新了一下)
  • 原文地址:https://www.cnblogs.com/gcfer/p/11076578.html
Copyright © 2011-2022 走看看