题目大意:

炮兵阵地 设置炮兵的位置 其上两位 下两位 左两位 右两位 不能同时设置炮兵

这题是 corn fields玉米地 的升级版 可以先看下这题的注释 更详细些

第一种方法是网上大多数题解的解法 https://blog.csdn.net/zwj1452267376/article/details/51387718

第二种方法是在第一种的基础上

预处理出每一行的可能状态,并直接保存其对应的下标 i , 这样可以通过下标 i ,

直接找到对应的状态 may[i] 和该状态对应的1的个数 num[i] ,而不需要另外将行数与状态及个数对应存储

将其建成邻接表的形式

这样在枚举每一行的状态时 只要查询邻接表就行

不需要枚举每种状态再去判断其是否能够对应该行的映像

而找到该行邻接表中存放的状态下标 直接得到该状态及个数

预处理出第一行的dp[][][],再依据第一行处理出第二行的dp[][][]

这样在处理之后的各行时 就可以直接判断该行的前两行的状态了

/// 第一种方法
#include <bits/stdc++.h>
using namespace std;
int n,m,may[],num[];
int mir[],dp[][][];
int getnum(int w)
{ // 计算w中1的个数
int cnt=;
while(w) {
cnt+=(w & );
w >>= ;
}
return cnt;
}
int main()
{
while(~scanf("%d%d",&n,&m)) {
int len=;
for(int i=;i<(<<m);i++) // 预处理m列所有可能状态及其1的个数
if((i&(i<<))== && (i&(i<<))== && ((i<<)&(i<<))==))
may[len]=i,num[len++]=getnum(i);
//for(int i=0;i<len;i++) printf("%d %d\n",may[i],num[i]);
memset(mir,,sizeof(mir));
for(int i=;i<n;i++) {
char c[]; scanf("%s",c);
for(int j=;j<m;j++)
if(c[j]=='H') mir[i]|=<<j; // 处理出每一行的映像 利于寻找可能状态
}
memset(dp,,sizeof(dp));
for(int i=;i<len;i++) // 预处理第一行
if((mir[]&may[i])==)
dp[][i][]=max(dp[][i][],num[i]);
for(int i=;i<len;i++) // 预处理第二行
if((mir[]&may[i])==)
for(int j=;j<len;j++)
if((may[j]&mir[])== && (may[j]&may[i])==)
dp[][i][j]=max(dp[][i][j],dp[][j][]+num[i]);
for(int i=;i<n;i++) { // 枚举更新的行数
for(int j=;j<len;j++) { // 枚举i行的可能状态
if((may[j]&mir[i])==) {
for(int k=;k<len;k++) { // 枚举i-1行的可能状态
if((may[k]&mir[i-])== && (may[j]&may[k])==) {
for(int p=;p<len;p++) { // 枚举i-2行的可能状态
if((may[p]&mir[i-])== && (may[p]&may[k])== && (may[j]&may[p])==)
{ dp[i][j][k]=max(dp[i][j][k],dp[i-][k][p]+num[j]); }
}
}
}
}
}
}
int ans=;
for(int i=;i<len;i++)
for(int j=;j<len;j++)
ans=max(ans,dp[n-][i][j]);
printf("%d\n",ans);
}
return ;
}
/// 第二种方法
#include <bits/stdc++.h>
using namespace std; int n,m,len; // 将图转为0 1图,1表示该位置可放炮兵
int may[], num[]; // may[]保存m列的所有可能状态, num[]保存对应下标的may[]保存的状态包含几个1
int dp[][][]; // dp[i][j][k]=到i行为止1的总个数 i行状态为may[j],i-1行状态为may[k]
vector <int> sta[]; // 保存每行所有的可能状态对应的下标 int get_num(int w)
{ // 得到w中有几个1
int cnt=;
while(w) {
cnt+=(w & );
w >>= ;
}
return cnt;
}
void init()
{ // m最大为10 先预处理出10列的所有可能状态
for(int i=;i<(<<);i++)
if((i&(i<<))== && (i&(i<<))==
&& ((i<<)&(i<<))==)
may[len]=i, num[len++]=get_num(i);
}
void save_sta(int row,int mir)
{ // 保存row行的可能状态的对应下标,mir为row行的映像
sta[row].clear();
for(int i=;i<len;i++) {
if(may[i]>=(<<m)) break; // 超过了m列的状态 直接忽略
if(may[i]&mir) continue; // 不是row行的可能状态 则跳过
sta[row].push_back(i); /// 保存符合的状态的对应下标
}
} int main()
{
init();
while(~scanf("%d%d",&n,&m)) {
for(int i=;i<n;i++) {
char c[]; scanf("%s",c);
int mir=;
for(int j=;j<m;j++) // P为可放 H为不可放
if(c[j]=='H') mir|=<<j; /// 处理出一个反过来的映像
save_sta(i,mir); /// 利于与所有状态对照
} memset(dp,,sizeof(dp));
for(int i=;i<sta[].size();i++) {
int t=sta[][i], mt=may[t], nt=num[t];
/// t即为可能状态的对应下标 则 may[t]为可能状态 num[t]为该状态中的1的数量
dp[][t][]=max(dp[][t][],nt); // 更新第1行
// 第一行只需考虑本身状态 for(int j=;j<sta[].size();j++) {
int t1=sta[][j], mt1=may[t1], nt1=num[t1];
if(mt1&mt) continue;
// 第二行只需考虑第一行的状态与其是否冲突 dp[][t1][t]=max(dp[][t1][t],dp[][t][]+nt1); // 更新第二行
}
} for(int i=;i<n;i++) { // 更新第i行时, 需考虑i-1及i-2行是否冲突
for(int j=;j<sta[i].size();j++) { // 枚举第i行状态
int t1=sta[i][j], mt1=may[t1], nt=num[t1]; for(int k=;k<sta[i-].size();k++) { // 枚举i-1行状态
int t2=sta[i-][k], mt2=may[t2];
if(mt1&mt2) continue; // i与i-1冲突则跳过 for(int p=;p<sta[i-].size();p++) { // 枚举i-2行的状态
int t3=sta[i-][p], mt3=may[t3];
if((mt2&mt3) || (mt1&mt3)) continue; // i-2与i-1冲突 i-2与i冲突 则跳过 dp[i][t1][t2]=max(dp[i][t1][t2],dp[i-][t2][t3]+nt);
} /// i行t1状态(i-1为t2)= max{ i-1行t2状态(i-2为t3) + i行1的个数 }
}
}
} int ans=-;
for(int i=;i<sta[n-].size();i++) {
int t1=sta[n-][i];
for(int j=;j<sta[n-].size();j++) {
int t2=sta[n-][j];
ans=max(ans,dp[n-][t1][t2]);
} /// 最后一行各种可能状态的最大值
}
printf("%d\n",ans);
} return ;
}

炮兵阵地 /// 状压DP oj26314的更多相关文章

  1. TZOJ 4912 炮兵阵地(状压dp)

    描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P" ...

  2. 洛谷P2704 [NOI2001]炮兵阵地 [状压DP]

    题目传送门 炮兵阵地 题目描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图 ...

  3. POJ1185 炮兵阵地 —— 状压DP

    题目链接:http://poj.org/problem?id=1185 炮兵阵地 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions ...

  4. poj - 1185 炮兵阵地 状压DP 解题报告

    炮兵阵地 Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 21553   Accepted: 8363 Description ...

  5. luogu 2704 炮兵阵地 状压dp

    状压的基础题吧 第一次看感觉难上天,后来嘛就.. 套路:先根据自身状态筛出可行状态,再根据地图等其他限制条件筛选适合的状态加入答案 f i,j,k 分别代表 行数,本行状态,上行状态,再累加答案即可 ...

  6. POJ 1185 炮兵阵地 状压dp

    题目链接: http://poj.org/problem?id=1185 炮兵阵地 Time Limit: 2000MS Memory Limit: 65536K 问题描述 司令部的将军们打算在N*M ...

  7. [NOI2001]炮兵阵地 状压DP

    题面: 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图.在每一格平原地形上最多 ...

  8. [POJ1185][NOI2001]炮兵阵地 状压DP

    题目链接:http://poj.org/problem?id=1185 很裸的状压,考虑对于一行用二进制储存每一种的状态,但是状态太多了做不了. 观察到有很多状态都是不合法的,于是我们预处理出合法的状 ...

  9. P2704 [NOI2001]炮兵阵地 (状压DP)

    题目: P2704 [NOI2001]炮兵阵地 解析: 和互不侵犯一样 就是多了一格 用\(f[i][j][k]\)表示第i行,上一行状态为\(j\),上上行状态为\(k\)的最多的可以放的炮兵 发现 ...

随机推荐

  1. NX二次开发-UFUN获取对象的显示属性(图层,颜色,空白状态,线宽,字体,高亮状态)UF_OBJ_ask_display_properties

    NX9+VS2012 #include <uf.h> #include <uf_modl.h> #include <uf_obj.h> UF_initialize( ...

  2. IntelliJ + Maven + 内Jetty 实现热部署项目

    部署的好处:代码修改后,不必关闭Jetty再重新启动,Maven启动时间不太和谐. 环境: IntelliJ IDEA11.1.4, Maven2.2.1 Jetty8.1.5 步骤: 1,在pom. ...

  3. APC注入DLL(win7下有问题)

    void APCKernelRoutine(PKAPC pKAPC, PKNORMAL_ROUTINE pUserAPC, PVOID pContext, PVOID pSysArg1, PVOID  ...

  4. 杂项:CSS3

    ylbtech-杂项:CSS3 1.返回顶部 1. CSS3是CSS(层叠样式表)技术的升级版本,于1999年开始制订,2001年5月23日W3C完成了CSS3的工作草案,主要包括盒子模型.列表模块. ...

  5. sklearn 调用逻辑回归函数训练数据时出现 “unknown label type:unknown”

    problemsolution:

  6. npm -v 报错:cannot find module 'core-util-is'

    今天想打开之前的项目运行看看,结果报错:cannot find module 'core-util-is',以为只是缺少模块core-util-is,然后npm install --save core ...

  7. Java oop第05章_多态、接口

    一. 为什么需要接口? Java中当一个类继承父类时,最多也只能继承一个父类,扩展性会受到一定的限制,为了弥补这一缺陷,Java又提供了一种新的引用数据类型分类,叫接口. 一个类只能继承一个父类,但可 ...

  8. Windows7 打开word2003提示:向程序发送命令时出现错误 解决方案

    1.关闭所有打开的Word文档:(包括任务管理器里的进程)2.复制这条命令:%appdata%\microsoft\templates3.开始 → 运行 → 粘贴上面复制的命令 → 确定4.在打开的目 ...

  9. 【学术篇】SPOJ COT 树上主席树

    这是学完主席树去写的第二道题_(:з」∠)_ 之前用树上莫队水过了COT2... 其实COT也可以用树上莫队水过去不过好像复杂度要带个log还是怎么样可能会被卡常数.. 那就orz主席吧.... 写了 ...

  10. PHP算法之盛最多水的容器

    给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) .在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0).找出其中的两条线, ...