• 【洛谷题解/NOI2001】P2704/NOI2001炮兵阵地


    原题链接:https://www.luogu.com.cn/problem/P2704
    难度:提高+/省选-
    涉及知识点:状态压缩DP

    题意

    在一个 n × m n\times m n×m 的方阵上,有平原( P )或山地( H ),只有在平原上才能放炮兵部队。炮兵部队的射程范围是上、下、左、右各延展2格。求在各炮兵部队不会互相攻击到的情况下,最多能够放置多少个炮兵部队。

    分析与解决

    这道题着眼一看,是一道很经典的棋盘式状态压缩DP,是对【SCOI2005】互不侵犯一题的简单扩展,主要是攻击范围由 1 格提升到了 2 格。

    在 【互不侵犯】 一题中,我们对状态的合法性检查时每两列一查,而对状态转移的合法性检查也是每两行一查。那么扩展到 【炮兵阵地】 这题,我们就可以考虑每三行一检查即可。

    f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k] 为摆完前 i i i 行后,第 i − 1 i-1 i1 行的状态为 j j j,第 i − 2 i-2 i2 行的状态为 k k k 的状态表示。在输入时,为了方便后续处理山地的问题,我们用 0 表示平原,用 1 表示山地。首先预处理所有合法状态,不合法的状态就是当第 i − 2 i-2 i2 行为 1 时(固定),第 i i i 行或第 i − 1 i-1 i1 行中的任意一行也为 1,此时无法部署炮兵部队,无法转移到这种状态。由于最后答案要求最多可以部署的炮兵部队数量,我们也需要在预处理时预处理各状态的炮兵部队数量。

    三层循环行数、第 i − 1 i-1 i1 行状态、第 i i i 行状态,第 i − 2 i-2 i2 行状态,如果三种状态之间存在同一列有多于 1 个的炮兵部队,那么不合法;如果第 i − 1 i-1 i1 行和第 i i i 行的对应位置为山地,则无法部署炮兵部队,不合法。状态转移方程为:
    f [ i ] [ j ] [ k ] = max ⁡ { f [ i − 1 ] [ i − 2 ] [ i − 1 ] + c n t [ i − 1 ] } f[i][j][k]=\max\left\{f[i-1][i-2][i-1]+cnt[i-1]\right\} f[i][j][k]=max{f[i1][i2][i1]+cnt[i1]}

    AC代码

    #include 
    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    const int N = 15, M = 1 << 10;
    
    int n, m;
    int g[110];
    vector <int> state;
    int f[2][M][M], cnt[M];
    
    bool check(int state)
    {
    	for (int i = 0; i < m; i++)
    	{
    		if ((state >> i & 1) && ((state >> i + 1 & 1) || (state >> i + 2 & 1))) return false;
    	}
    	return true;
    }
    
    int count(int state)
    {
    	int res = 0;
    	for (int i = 0; i < m; i++) res += state >> i & 1;
    	return res;
    }
    
    int main()
    {
    	cin >> n >> m;
    	for (int i = 1; i <= n; i++)
    	{
    		for (int j = 0; j < m; j++)
    		{
    			char c;
    			cin >> c;
    			if (c == 'H') g[i] += 1 << j;
    		}
    	}
    	
    	for (int i = 0; i < 1 << m; i++)
    	{
    		if (check(i)) 
    		{
    			state.push_back(i);
    			cnt[i] = count(i);
    		}
    	}
    	
    	for (int i = 1; i <= n + 2; i++)
    	{
    		for (int j = 0; j < state.size(); j++)
    		{
    			for (int k = 0; k < state.size(); k++)
    			{
    				for (int u = 0; u < state.size(); u++)
    				{
    					int a = state[j], b = state[k], c = state[u];
    					if ((a & b) || (b & c) || (a & c)) continue;
    					if (g[i - 1] & a | g[i] & b) continue;
    					f[i & 1][j][k] = max(f[i & 1][j][k], f[i - 1 & 1][u][j] + cnt[b]);
    				}
    			}
    		}
    	}
    	
    	cout << f[n + 2 & 1][0][0];
    	return 0;
    } 
    
  • 相关阅读:
    如何在Docker容器中安装RabbitMQ
    Electronica上海 Samtec 验证演示 | FireFly™Micro Flyover System™
    快速搭建开源分布式任务调度系统DolphinScheduler并远程访问
    关于软件测试过程质量管理思考
    Vue3自定义指令(directive)
    【Apache Spark 】第 11 章使用 Apache Spark 管理、部署和扩展机器学习管道
    这份300页的2020最新java面试题及答案,“吃透”能让你成功定位阿里P9
    flink 1.6 sql gateway 测试记录
    【微服务】Nacos通知客户端服务变更以及重试机制
    基于注解的Spring MVC实例开发过程
  • 原文地址:https://blog.csdn.net/lightningcs/article/details/127034369