题解 | #炮兵阵地#

炮兵阵地

https://ac.nowcoder.com/acm/problem/16886

思路:

题目要求求出最多的炮兵数,对于一个位置可以选择放也可以不放,而之后可以根据这次的选择更新下一步的选择。考虑状态压缩dp。一行一行的放炮兵,因为题目中给出的炮兵攻击范围是一个十字,所以在判断这个炮兵能不能放的时候需要知道上一行炮兵和上上行放在哪了,也要知道此时放的炮兵所在的这一行里左边的放炮兵的情况,可以用一个01串来表示每一行放炮兵的情况,用位运算&来比较这一行与上一行或者上上行的情况。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=110;
int dp[N][70][70];//dp[i][j][k]表示放了i行,现在状态为j,之前状态为k的最大炮兵数
int n,m;
int M[N];
vector<int> num;
vector<int> st;

int cal(int i)
{
    int cnt=0;
    while(i)
    {
        if(i&1) cnt++;
        i>>=1;
    }
    return cnt;
}

int main(){
    cin>>n>>m;
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=m; j++)
        {
            char c;
            cin>>c;
            if(c=='H') M[i] |= (1<<(m-j));
/*把每一行的地形都当作01串,如果是山地,就初始化为1,否则为0.在
后面的操作中,放了炮兵的格子为1,如果(此时状态)&(这一行地形的01串值)
=1的话,就说明在山地上放了炮兵,那么这种情况就不行。如果值为0,
有3种情况:1、平原上放了炮兵 2、平原上没放炮兵3、山地上没放炮兵。
1<<(j-1)是反着存地图里的山地的,答案和正着存没区别。
*/
        }
    }
    
    for(int i=0; i<(1<<m); i++)//先把一整行可行的情况存下来,到用的时候就不用再算一遍了,每种状态都是01串,1为放炮兵的点,0是不放炮兵
    {
        if(i & (i<<1)) continue;//如果有两个相邻的1,跳过
        if(i & (i<<2)) continue;//如果有两个1只相差1位,跳过
        num.push_back(cal(i));//num存这一种情况下有几个炮兵
        st.push_back(i);//st存这一种情况的01串
    }
    int ans=0;
    for(int i=1; i<=n; i++)
    {
        for(int j=0; j<st.size(); j++)
        {
            int cur=st[j];
            if(cur & M[i]) continue;//如果在山地上放炮兵,跳过
            for(int k=0; k<st.size(); k++)
            {
                int last=st[k];
                if(cur & last) continue;//如果现在状态和上一次状态有某个炮兵在同一列,跳过(注意:上一行炮兵在这一行炮兵的斜上方是没问题的,他们只是攻击范围重叠了)
                for(int u=0; u<st.size(); u++)
                {
                    int tmp=st[u];
                    if(tmp & last) continue;//如果上一次状态和上上次状态有某个炮兵在同一列,跳过
                    if(tmp & cur) continue;//如果现在状态和上上次状态有某个炮兵在同一列,跳过
                    dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][u]+num[j]);//直接用i、j、k,就是用状态的编号来表示,节约空间
                    ans=max(dp[i][j][k],ans);
                }
            }
        }
    }
    
    cout<<ans<<endl;
    
    return 0;
}
全部评论

相关推荐

冲芭芭拉鸭:你这图还挺新,偷了。
投递美团等公司10个岗位
点赞 评论 收藏
分享
贺兰星辰:不要漏个人信息,除了简历模板不太好以外你这个个人简介是不是太夸大了...
点赞 评论 收藏
分享
评论
点赞
收藏
分享
正在热议
# 25届秋招总结 #
442570次浏览 4512人参与
# 春招别灰心,我们一人来一句鼓励 #
41986次浏览 533人参与
# 北方华创开奖 #
107436次浏览 599人参与
# 地方国企笔面经互助 #
7964次浏览 18人参与
# 同bg的你秋招战况如何? #
76743次浏览 563人参与
# 实习必须要去大厂吗? #
55775次浏览 961人参与
# 阿里云管培生offer #
120264次浏览 2220人参与
# 虾皮求职进展汇总 #
115687次浏览 886人参与
# 如果你有一天可以担任公司的CEO,你会做哪三件事? #
11584次浏览 287人参与
# 实习,投递多份简历没人回复怎么办 #
2454714次浏览 34857人参与
# 提前批简历挂麻了怎么办 #
149906次浏览 1977人参与
# 在找工作求抱抱 #
906025次浏览 9421人参与
# 如果公司给你放一天假,你会怎么度过? #
4757次浏览 55人参与
# 你投递的公司有几家约面了? #
33206次浏览 188人参与
# 投递实习岗位前的准备 #
1195950次浏览 18549人参与
# 机械人春招想让哪家公司来捞你? #
157635次浏览 2267人参与
# 双非本科求职如何逆袭 #
662248次浏览 7397人参与
# 发工资后,你做的第一件事是什么 #
12734次浏览 62人参与
# 工作中,努力重要还是选择重要? #
35815次浏览 384人参与
# 简历中的项目经历要怎么写? #
86920次浏览 1516人参与
# 参加完秋招的机械人,还参加春招吗? #
20133次浏览 240人参与
# 我的上岸简历长这样 #
452024次浏览 8088人参与
牛客网
牛客企业服务