动态规划-状态压缩DP

例:炮兵阵地

【问题描述】

司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队。一个N*M的地图由N行M列组成,地图的每一格可能是山地(用"H" 表示),也可能是平原(用"P"表示),如下图。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:

如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。

【样例】

Input
第一行包含两个由空格分割开的正整数,分别表示N和M;接下来的N行,每一行含有连续的M个字符('P'或者'H'),中间没有空格。按顺序表示地图中每一行的数据。N <= 100;M <= 10。
Output
仅一行,包含一个整数K,表示最多能摆放的炮兵部队的数量。

【分析】

在任意一行上,最多10列,假设这10个位置都是平原,那么在这10个位置上放置炮兵并互不攻击,一共有60种方法。具体是哪60种方法,这个需要枚举一下。
用num[i]表示第i种方案放置的炮兵数量。比如:PPPPHHPPPP我们可以在第1个位置和第7个位置各放一个炮兵,这是一种可行的方案。此时num[i]=2
用dp[s][i][j]表示第s行使用第i种方案,第s-1行使用第j种方案时部队可以部署的最大值,那么max{dp[N][i][j], 其中i,j=1...60}的就是最后的答案
可行性?位运算
dp[s][i][j]=num[i]+max{dp[s-1][j][k],这表示:如果i,j,k这三种方案之间是相容的,那么dp[s][i][j] =num[i]+dp[s-1][j][k]

例:ZOJ4257-MostPowerful

【问题描述】

不超过10种气体,两两之间相互碰撞可以产生一定的能量,如a碰b,那么b气体就消失,自身不能碰自身,问最后所能得到的最大能量。

【分析】

用10位二进制表示气体是否存在,0表示存在,1表示不存在,S(上一个状态)中的两种气体碰撞并且有一种消失,可以得到newS的状态(状态转移)
dp[state] 状态为state时的最大能量,dp[state] = max(dp[state],dp[state']+a[i][j])
可行性?s&(1<<i)

例:POJ2411-Mondriaan's Dream

【问题描述】

一个矩阵,只能放1*2的木块,问将这个矩阵完全覆盖的不同放法有多少种。1<=h,w<=11

【分析】

如果是横着的就定义11,如果竖着的定义为竖着的01,这样按行dp只需要考虑两件事儿,当前行&上一行,是不是全为1,不是说明竖着有空(不可能出现竖着的00),另一个要检查当前行里有没有横放的,但为奇数的1。
dp[state][i]第i行状态为state时候的方案数
dp[state][i] += dp[state'][i-1] state'为i-1行的,不与i行状态state冲突的状态
可行性?1.检查当前行里有没有横放的,但为奇数的1,2.放满。

inline bool check2(int x1,int x2){
    if((x1|x2)!=full-1)//如果这里不用位运算,时间很长,约3000MS
        return false;
    return kexing(x1&x2);
}

猜你喜欢

转载自blog.csdn.net/u013228808/article/details/85220748