zoukankan      html  css  js  c++  java
  • [NOI2001]炮兵阵地 【状压DP】

    #(color{red}{mathcal{Description}})

    (Link)

    司令部的将军们打算在(N imes M)的网格地图上部署他们的炮兵部队。一个(N imes M)的地图由(N)(M)列组成,地图的每一格可能是山地(用“(H)” 表示),也可能是平原(用“(P)”表示)。并且事实上山地不能部署。 现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。

    #(color{red}{mathcal{Solution}})

    对于这个题而言,我们考虑状压(DP),但是状压的时候我们会发现,他的状态是跟前两行都有关系的。所以我们不妨考虑其状态为(dp_{i,j,k}),及前(i)行、第(i)行状态为(j)、第(i - 1)行状态为(k)的部队数量。那么很显然的状态转移方程是$$dp_{i,j,k} = max { dp_{i - 1, k, l} } +getlen(j)$$

    (emmm)我才不会告诉你一开始我把这个方程里面最后加的(getlen(j))写成了(+1)

    (Obviously)第一维是可以滚掉的……然后尽量还是把合法状态预处理一下比较好不预处理就会十分恶心并且我根本调不出来(ORZ)

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #define MAXN 1096
    
    using namespace std ;
    int tot, s[MAXN], getnum[MAXN ];
    int ans, i, j, k, l, d, Mx ; char c ;
    int N, M, List[MAXN], dp[2][MAXN][MAXN] ;
    
    inline int getL(int x){
    	int ret = 0 ; 
    	while(x){
    		if(x & 1) ret ++ ;
    		x >>= 1 ;
    	}
    	return ret ;
    }
    int main(){
    	cin >> N >> M ;
    	for(i = 1; i <= N; i ++)
    		for(j = 1; j <= M; j ++){
    			cin >> c ;
    			if(c == 'H') List[i] += 1 << j - 1 ;
    		} Mx = (1 << M) - 1 ;
    	for(i = 0; i <= Mx; i ++){
    		if((i & (i >> 1)) || (i & (i >> 2)) || (i & (i << 1)) || (i & (i << 2)))
    			continue ;
    		++ tot, s[tot] = i ; 
    		getnum[tot] = getL(i) ;
    		if(List[1] & i) continue ;
    		dp[1][0][tot] += getnum[tot] ;
    	}
    	for(i = 1; i <= tot; i ++)
    		for(j = 1; j <= tot; j ++){
    			if((s[i] & s[j]) || (s[i] & List[1]) || (s[j] & List[2])) continue ;
    			dp[0][i][j] = max(dp[0][i][j], dp[1][0][i] + getnum[j]) ;
    		}
    	for(d = 1, i = 3; i <= N; i ++, d ^= 1){
    		memset(dp[d], 0, sizeof(dp[d])) ;
    		for(j = 1; j <= tot; j ++){
    			if(s[j] & List[i]) continue ;
    			for(k = 1; k <= tot; k ++){
    				if((s[j] & s[k]) || (s[k] & List[i - 1])) continue ;
    					for(l = 1; l <= tot; l ++)
    						if((s[l] & s[k]) || (s[l] & s[j]) || (s[l] & List[i - 2])) continue ;
    						else  dp[d][k][j] = max(dp[d][k][j], dp[d ^ 1][l][k] + getnum[j]) ;
    			}
    		}
    	}
    	for(i = 1; i <= tot; i ++)
    		for(j = 1; j <= tot; j ++)
    			ans = max(ans, dp[N & 1][i][j]) ;
    	cout << ans ;
    }
    
  • 相关阅读:
    js去除字符串空格(空白符)
    jq以固定开头的class属性的名称
    day--38 mysql表的完整性约束总结
    day--39-MySQL的多表查询
    day--40 mysql-视图,触发器,存储过程,函数总结
    day--41 mysql索引原理与慢查询优化
    day--42 前端基础小结
    day--43 HTML标签和CSS基本小结
    day46----JavaScript的函数及对象小结
    JavaScript正则表达式
  • 原文地址:https://www.cnblogs.com/pks-t/p/9406924.html
Copyright © 2011-2022 走看看