zoukankan      html  css  js  c++  java
  • 洛谷2704 [NOI2001]炮兵阵地

    题目戳这里
    Solution

    状压DP很好的入门题,用熟练位运算貌似也没那么难。

    首先分析一下题目:
    看见n=100,m=10,立马就想到了状压,看起来也像DP,所以我们还是采用行号为阶段的状压DP。
    因为每个炮兵可以攻击到上面两行的范围,所以枚举i行状态时需要知道i-1和i-2行的状态。我们把每一行的状态看成一个M位的二进制数,第p位为1代表该行第p列放置了一个炮兵,0代表没有。
    在DP前,我们先预处理出集合S,代表“相邻两个1的距离不小于3”的所有M位二进制数,g数组储存对应S集合中某个数含有的1的个数。然后还需要预处理出1行和2行状态。
    那么状态定义也很明显了,f[j][k][i]表示第i行状态为j,第i-1行状态为k的方案数,那么只需枚举上一行状态和上两行状态便可以转移。
    虽然M为的二进制数有(2^M)个,但是我们只枚举S集合里面的数(其他的不合法),所以时间复杂度为(O(N|S|^2)),事实上S集合非常小。

    Coding

    #include<bits/stdc++.h>
    using namespace std;
    const int N	 = 105;
    int num,S[N*20],ans,n,m,f[N*20][N*20][101],sum[N*20],a[N],g[N];
    int count(int x)
    {
        int num=0;
        while(x) 
        {
            if(x%2==1) num++;
            x/=2;
        }
        return num;
    }
    int main()
    {
        char x;
        cin>>n>>m;
        for(int i=1;i<=n;i++)
            for(int j=0;j<m;j++)
            { cin>>x; if(x=='H') a[i]+=1<<j;}
        for(int i=0;i<(1<<m);i++)//预处理S集合
            if(((i&(i<<1))==0)&&((i&(i<<2))==0)&&((i&(i>>1))==0)&&((i&(i>>2))==0))
            {
                S[++num]=i;
                g[num]=count(i);
                if((i&a[1])==0) f[0][num][1]=g[num];
            }
        for(int i=1;i<=num;i++)//预处理前两行
            for(int j=1;j<=num;j++)
            if(((S[i]&S[j])==0)&&((S[j]&a[2])==0))  f[i][j][2]=max(f[i][j][2],f[0][i][1]+g[j]);
        for(int i=3;i<=n;i++)
            for(int j=1;j<=num;j++)
            if((a[i]&S[j])==0)
                for(int k=1;k<=num;k++)
                    if((S[k]&S[j])==0)
                        for(int last=1;last<=num;last++)
                            if(((S[last]&S[k])==0)&&((S[last]&S[j])==0)) f[k][j][i]=max(f[k][j][i],f[last][k][i-1]+g[j]);
        for(int i=1;i<=num;i++)
            for(int j=1;j<=num;j++)
            ans=max(ans,f[i][j][n]);
        cout<<ans;
        return 0;
    }
    
  • 相关阅读:
    layui + mvc + ajax 导出Excel功能
    PL/SQL Developer工具包和InstantClient连接Oracle 11g数据库
    .NET中JSON的序列化和反序列化的几种方式
    C# 编程中的堆栈(Stack)和队列(Queue)
    Oracle 数据库常用操作语句大全
    C#方法中参数ref和out的解析
    JS实现限行
    ajax+ashx 完美实现input file上传文件
    HTML5 学习
    Linux文件和目录操作管理命令
  • 原文地址:https://www.cnblogs.com/Le-mon/p/9625529.html
Copyright © 2011-2022 走看看