poj 1185(状态压缩DP)
poj 1185(状态压缩DP)
题意:在一个N*M的矩阵中,‘H'表示不能放大炮,’P'表示可以放大炮,大炮能攻击到沿横向左右各两格,沿纵向上下各两格,现在要放尽可能多的大炮使得,大炮之间不能相互攻击。
解析:可以发现,对于每一行放大炮的状态,只与它上面一行和上上一行的状态有关,每一行用状态压缩的表示方法,0表示不
放大炮,1表示放大炮,同样的,先要满足硬件条件,即有的地方不能放大炮,然后就是每一行中不能有两个1的距离小于
2(保证横着不互相攻击),这些要预先处理一下。然后就是状态表示和转移的问题了,因为是和前两行的状态有关,所以要开
个三维的数组来表示状态,当前行的状态可由前两行的状态转移而来。即如果当前行的状态符合前两行的约束条件(不和前两
行的大炮互相攻击),则当前行的最大值就是上一个状态的值加上当前状态中1的个数(当前行放大炮的个数)
状态表示:dp[i][j][k] 表示第i行状态为k,第i-1状态为j时的最大炮兵个数。
状态转移方程:dp[i][j][k] =max(dp[i][j][k],dp[i-1][l][j]+cot[k]); cot[k]为k状态中1的个数 ,可用位运算求得
DP边界条件:dp[1][0][i] =cot[i] 状态i能够满足第一行的硬件条件
AC代码如下:
#include<stdio.h>
int sta[<<],cot[<<],cur[],dp[][][];
char g[][];
int n,m,num;
int max(int a,int b)
{
return a>b?a:b;
}
void init() //预处理所有可能出现的状态
{
int i,tmp,sum,count;
num=;
sum=<<m;
for(i=;i<sum;i++)
{
if(i&(i<<) || i&(i<<)) //同一行中1的距离不能小于2
continue;
sta[num]=i;
count=;
tmp=i;
while(tmp) //求该状态中的二进制表示中1的个数
{
count++;
tmp&=(tmp-); //将最低位的1化为0
}
cot[num++]=count;
}
}
int fit(int x,int y) //判断上下两行对应位置是否同为1
{
if(x&y)
return ;
return ;
}
void DP()
{
int i,j,k,l;
for(i=;i<num;i++) //预处理第1行的情况
{
if(!fit(sta[i],cur[]))
continue;
dp[][][i]=cot[i];
}
for(i=;i<=n;i++)
{
for(j=;j<num;j++)
for(k=;k<num;k++)
{
if(!fit(sta[k],cur[i]) || !fit(sta[j],cur[i-]) || !fit(sta[k],sta[j])) //排除不符合条件的状态
continue;
for(l=;l<num;l++)
{
if(!fit(sta[l],cur[i-]) || !fit(sta[k],sta[l]) || !fit(sta[j],sta[l]) || !dp[i-][l][j]) //排除不符合条件的状态
continue;
dp[i][j][k]=max(dp[i][j][k],dp[i-][l][j]+cot[k]); //状态转移
}
}
}
int ans=;
for(i=;i<=n;i++) //求最多放置多少大炮
for(j=;j<num;j++)
for(k=;k<num;k++)
ans=max(ans,dp[i][j][k]);
printf("%d\n",ans);
}
int main()
{
int i,j;
char c;
scanf("%d%d",&n,&m);
for(i=;i<=n;i++)
{
getchar();
for(j=;j<=m;j++)
{
scanf("%c",&c);
if(c=='H') //用二进制表示不能放置大炮的情况,便于判断
cur[i]+=<<(m-j); //网上大多数的题解都是cur[i]+=1<<(j-1);反过来了,我表示很不理解,但是能AC =_=||~~~
}
}
init();
DP();
return ;
}
poj 1185(状态压缩DP)的更多相关文章
- POJ 1185 状态压缩DP 炮兵阵地
题目直达车: POJ 1185 炮兵阵地 分析: 列( <=10 )的数据比较小, 一般会想到状压DP. Ⅰ.如果一行10全个‘P’,满足题意的状态不超过60种(可手动枚举). Ⅱ.用DFS ...
- POJ 1185 状态压缩DP(转)
1. 为何状态压缩: 棋盘规模为n*m,且m≤10,如果用一个int表示一行上棋子的状态,足以表示m≤10所要求的范围.故想到用int s[num].至于开多大的数组,可以自己用DFS搜索试试看:也可 ...
- poj 2923(状态压缩dp)
题意:就是给了你一些货物的重量,然后给了两辆车一次的载重,让你求出最少的运输次数. 分析:首先要从一辆车入手,搜出所有的一次能够运的所有状态,然后把两辆车的状态进行合并,最后就是解决了,有两种方法: ...
- poj 2688 状态压缩dp解tsp
题意: 裸的tsp. 分析: 用bfs求出随意两点之间的距离后能够暴搜也能够用next_permutation水,但效率肯定不如状压dp.dp[s][u]表示从0出发訪问过s集合中的点.眼下在点u走过 ...
- Mondriaan's Dream(POJ 2411状态压缩dp)
题意:用1*2的方格填充m*n的方格不能重叠,问有多少种填充方法 分析:dp[i][j]表示i行状态为j时的方案数,对于j,0表示该列竖放(影响下一行的该列),1表示横放成功(影响下一列)或上一列竖放 ...
- poj 2411 状态压缩dp
思路:将每一行看做一个二进制位,那么所有的合法状态为相邻为1的个数一定要为偶数个.这样就可以先把所有的合法状态找到.由于没一层的合法状态都是一样的,那么可以用一个数组保存.由第i-1行到第i行的状态转 ...
- poj 3254 状态压缩DP
思路:把每行的数当做是一个二进制串,0不变,1变或不变,找出所有的合法二进制形式表示的整数,即相邻不同为1,那么第i-1行与第i行的状态转移方程为dp[i][j]+=dp[i-1][k]: 这个方程得 ...
- poj 1185 状态压缩
炮兵阵地 Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 27926 Accepted: 10805 Descriptio ...
- POJ 3254 状态压缩 DP
B - Corn Fields Crawling in process... Crawling failed Time Limit:2000MS Memory Limit:65536KB ...
随机推荐
- 4515: [Sdoi2016]游戏
4515: [Sdoi2016]游戏 链接 分析: 树链剖分 + 超哥线段树.注意细节. 代码: #include<cstdio> #include<algorithm> #i ...
- [CQOI2015]任务查询系统 主席树
[CQOI2015]任务查询系统 LG传送门 以前还没见过主席树的这种写法. 考虑使用差分的思想处理每一个任务,然后所有的东西就都能顺理成章地用主席树维护了,查询的时候和平时的主席树有一点不同,详见代 ...
- javaweb 报表生成(pdf excel)所需要用到的技术和思路
pdf: “ 目前开源.成熟.稳定的第三方包只有iText.而用iText生成PDF有三种方式: 调用iText API,用代码“写”出PDF,依赖包:com.itextpdf:itextpdf:5. ...
- 初窥Linux之我最常用的20条命令
1.cd命令 这是一个非常基本,也是大家经常需要使用的命令,它用于切换当前目录,它的参数是要切换到的目录的路径,可以是绝对路径,也可以是相对路径.如: cd /root/Docements # 切 ...
- python应用:生成简单二维码
概述 \(\quad\)第一篇python的应用就打算写一写用python生成简单的二维码啦.因为二维码在日常生活中越来越常用了,部分博客也用二维码来用作打赏的工具.但是要提醒大家的是,千万不要乱扫街 ...
- 宏基4752g 开机进度条卡到75%左右,解决办法
起因:更新win10推送的更新补丁,失败自动回退.开机进度条只能走到75%,bios进不去,最后就卡在开机的logo.(还有其他人是win7直接升级win10,也出现了这种情况.)解决办法:重刷bio ...
- 写高并发程序时慎用strncpy和sprintf
分享一下最近做程序优化的一点小心得:在写高并发交易代码时要谨慎使用strncpy和sprintf. 下面详细介绍一下这样说的原因及建议实践: 1 慎用strncpy因为它的副作用极大 我们平时使用st ...
- MySQL事务及其实现
事务定义 事务是访问并更新数据库中各个数据项的一个程序执行单元.在事务操作中,要不都做修改,要么都不做. 事务特性 事务具有ACID四个特性,分别是:原子性(Atomicity).一致性(Consis ...
- play-with-vim1~5
1.移动 h,j,k,l分别对应左下上右 2.模式 vim有四种模式:普通模式,插入模式,可视模式,命令行模式 进入vim 默认为普通模式,光标为方块 输入i 进入插入模式,窗口左下角为insert ...
- shell中中括号的使用
原文出处:https://www.jianshu.com/p/855c9fb373ff Shell 里面的方括号(包括单中括号与双中括号)可用于以下三种情况的判断: 算术比较. 比如一个变量是否为0, ...