zoukankan      html  css  js  c++  java
  • 炮兵阵地

    这是一道很不错的状压题

    题目,数据,实现都不错

    除了for循环打的头痛。。。

    我们来康康这道题

    首先,这是一道状压DP,因为数据量比较状压。。。

    分别有N*M的地图,有缺陷的地形以及十字形的覆盖范围。

    然后我们定义状态:

    F[i][j][k]

    用 i 表示当前枚举到第几行,j表示当前行的状态,k表示上一行的状态

    因为每一行的值会受前两行的影响,上面第一行方便枚举,但是再枚举上面第一行就有点吃力,因为这样我们的值没办法保证互补干涉,导致哇(WA)掉,于是我们用本行和上一行的排列状态表示一个状态。

    然后我来说说状压(毕竟我没看太懂,知道蒙蔽的痛苦(神犇们可以跳过直接看码))

    我们是用一个数的二进制展开来表示状态的

    比如说8表示 1000就是第一个位置选,其余不选,而每种二进制数代表不同的选择序列,用状态压缩的方式进行压缩处理,可以使用一维来代替好多维,使用时一般预处理一个“不能选的”数,它也是一个压缩过的树,用它的值来表示那个位置不可以选,而我们枚举的是一整个选择的状态,所以只要(&)后操作出现不是期望的值,就可以判定它不符合题意

    1 0 0 1 0 0 1  S1

    1 1 1 0 1 1 0  S2

    若S2中0表示不能选,就有(s1&s2!=s1)(s1表示1的位置选择,与不能选的冲突)。

    同理,当判断是否与上一行冲突时,就有(s1&s2==0)表示不冲突(即没有两列位置重合的),这样以后,就可以进行操作了。。。

    康康代码

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,F[105],f[105][66][66],start[70],cnt=0,gs[200];//特殊记录,不爆空间
    bool mp[105][30];
    
    int main(){
        cin>>n>>m;
        char a; 
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                cin>>a; 
                if(a=='H')mp[i][j]=1;//另不能选的为1
            }
        }
    
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                F[i]=(F[i]<<1)+mp[i][j];
                //把每行“不可选”状态压缩起来方便实用
            }
        }
    
        start[++cnt]=0;
        /*这个尤为重要,如果你要空间时间,就得像下面一样存
        如果直接存的话,就没了(毕竟那个一整排H的数据还是有的)
        不过如果从0开始循环也可以,但是放在这里起警示作用233*/
    
        for(int i=1;i<(1<<m);i++){
            if(i&(i<<1))continue;   //因为左二右二不能选
            if(i&(i<<2))continue;
            if(i&(i>>1))continue;
            if(i&(i>>2))continue;
            start[++cnt]=i;//直接存有用的就行
            int x=i;
            while(x){       //求取每个状态的贡献
                gs[cnt]++;
                x-=(x&(-x));
            }
        }
    
        for(int i=1;i<=cnt;i++){    //处理第一排
            if((start[i]&F[1])==0){ //不能与地形冲突
                f[1][i][0]=gs[i];
            }   
        }
    
        for(int i=1;i<=cnt;i++){    //第二排
            if((start[i]&F[2])==0)
            for(int j=1;j<=cnt;j++){
                if((start[i]&start[j])==0&&(start[j]&F[1])==0){
                        //判断是否冲突
                    f[2][i][j]=gs[j]+gs[i];
                } 
            }
        }
        //让for来的更猛烈些吧(枚举状态)
        for(int i=3;i<=n;i++){      
            for(int j=1;j<=cnt;j++){    //当前一排状态        
                if((start[j]&F[i])==0){ 
                    for(int k1=1;k1<=cnt;k1++){     //上面第一排         
                        if((start[j]&start[k1])==0&&(start[k1]&F[i-1])==0){                     
                            for(int k2=1;k2<=cnt;k2++){ //上面第二排             
                                if((start[j]&start[k2])==0&&(start[k1]&start[k2])==0&&(start[k2]&F[i-2])==0){   
                                                //判断所有冲突情况
                                    f[i][j][k1]=max(f[i][j][k1],f[i-1][k1][k2]+gs[j]);//从之前转移过来就行
                                }
                            }
                        }
                    }
                }   
            }
        }
    
        int ans=0;
        //所有的值都在最后1排存,用这一排的所有情况的最大值当最大值
        for(int i=1;i<=cnt;i++){
            for(int j=1;j<=cnt;j++){
                ans=max(ans,f[n][i][j]);
            }
        }
        cout<<ans;
    }

    于是,这个就完了

    里面的状态转移还好说,这个判断冲突搞得我掉头发。。

    就这样吧,

    马蜂一般,希望能帮到您

  • 相关阅读:
    pythos.access()
    CSS简笔画:纯CSS绘制一艘邮轮
    【每日坚果】如何成为一名数据工匠?
    【博客园使用小指南】DIY美化博客园小指南--主题设置
    乐字节Java反射之一:反射概念与获取反射源头Class
    乐字节Java面向对象三大特性以及Java多态
    在乐字节学习的一天(持续跟新……)
    在乐字节学习的一天(持续跟新……)
    乐字节Java变量与数据类型之二:Java常量与变量
    乐字节Java变量与数据类型之一:Java编程规范,关键字与标识符
  • 原文地址:https://www.cnblogs.com/you-xiao-mang-ci/p/11251220.html
Copyright © 2011-2022 走看看