ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

P2704 [NOI2001] 炮兵阵地 -状态压缩dp -省选

2022-07-31 12:00:22  阅读:132  来源: 互联网

标签:std 省选 cin char ++ int NOI2001 P2704


#include <bits/stdc++.h>
#define debug(x) std::cerr << "Line: " << __LINE__ << \
                    "," << #x << "=" << x << "\n"
using ll = long long;
constexpr int N = 105;
int a[N];
// dp[上上行01状态][上行01状态][滚动]
int dp[1 << 10][1 << 10][3], sum[1 << 10];
int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    int n, m;
    std::cin >> n >> m;
    char x;
    for(int i = 0; i < n; i++){
        for(int j = 0; j < m; j++){
            std::cin >> x;
            if(x == 'H') a[i] |= (1 << j);//如果是山,那一位就是1
        }
    }
    for(int i = 0; i < (1 << m); i++){
        sum[i] = __builtin_popcount(i);//提前计算好对于每一个十进制,1的个数
    }
    //枚举第一行的每一种摆放状态
    for(int S = 0; S < (1 << m); S++){
        /*
            同时满足三个条件:
            1. 刚好和第一行地形"交错"放置
            2. 每个位置的前一格没有炮
            3. 每个位置的前两格没有炮
        */
        if(!(S & a[0] || S & (S << 1) || S & (S << 2) )){
            dp[0][S][0] = sum[S];//第0行什么都没有,第一行是枚举的初始化状态,滚动:0, 所放置的炮个数
        }
    }

    //枚举第一、二行的每一种摆放状态
    for(int L = 0; L < (1 << m); L++){//枚举上排状态 O(2 ^ m)
        for(int S = 0; S < (1 << m); S++){//枚举这排状态 O(2 ^ m)
            /*
                转移满足的条件:
                1.满足上行和这行不冲突
                2.满足上行和第一行不冲突
                3.满足这行和第二行不冲突
                4.满足上行与自己前一格、两格不冲突
                5.满足这行与自己前一格、两格不冲突
            */
            if(!(L & S || L & a[0] || S & a[1] || (L & (L<<1)) ||
                 (L & (L<<2)) || (S & (S<<1)) || (S & (S<<2))))    {
                //谜之一长串特判
                dp[L][S][1] = sum[S] + sum[L];//将前两行的所放置炮的个数加起来
            }
        }
    }

    //初始化完成,可以借以上两个初始化数据向后滚动递推
    for(int i = 2; i < n; i++){//对于之后的行
        for(int L = 0; L < (1 << m); L++){//这一行的上上行
            /*
                特判
                1.上行摆放状态与上行地形冲突
                2.自己de摆放状态和自己冲突
            */
            if(L & a[i - 1] || L & (L << 1) || L & (L << 2)){
                continue;
            }
            for(int S = 0; S < (1 << m); S++){
                /*
                    特判
                    1.这行摆放状态与这行地形冲突
                    2.自己de摆放状态和自己冲突
                */
                if(S & a[i] || L & S || S & (S << 1) || S & (S << 2)){
                    continue;
                }
                for(int FL = 0; FL < (1 << m); FL++){
                    /*
                        特判
                        1.上上行摆放状态与上上行地形冲突
                        2.上上自己de摆放状态和自己冲突
                    */
                    if(FL & L || FL & S || FL & a[i - 2] || FL & (FL << 1) || FL & (FL << 2)){
                        continue;
                    }
                    //滚动更新,这个状态要么和原来的一样,要么转移
                    dp[L][S][i % 3] = std::max(dp[L][S][i % 3], dp[FL][L][(i - 1) % 3] + sum[S]);
                }
            }
        }
    }
    int ans = -1e9;
    for(int L = 0;L < (1 << m);L ++)
        for(int S = 0; S < (1 << m); S++)
            ans = std::max(ans,dp[L][S][(n - 1) % 3]);    //结束状态可以是最后一行的任何状态
    std::cout << ans;
    return 0;
}

 

标签:std,省选,cin,char,++,int,NOI2001,P2704
来源: https://www.cnblogs.com/zrzsblog/p/16536812.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有