poj 1185 炮兵阵地 [经典状态压缩DP]
2013-08-21 20:42
295 查看
题意:略。
思路:由于每个大炮射程为2,所以如果对每一行状态压缩的话,能对它造成影响的就是上面的两行。
这里用dp[row][state1][state2]表示第row行状态为state2,第row-1行状态为state1时最多可以安放多少大炮。
则递推公式为:dp[i][K][J] = max(dp[i-1][L][K] + num[J])。其中num[J]表示状态J的二进制形式里有多少个1。
代码我是参考的别人的,觉得写得很好。
主要有一下几个地方:
1. 在判断一个数二进制形式有多少个1时,用 x & (x - 1) (具体见代码count_one函数)来判断。这种方法的时间复杂度就是x的二进制中1的个数。
假设有一个数二进制形式为1000位,其中只有一个1,则用最普通方法一位一位来数则需要计算1000次,而用该方法就是1次。
2. 在判断一个状态是否合法时(即该状态内不能有两个1距离在2以内),用x & (x << 1),x & (x << 2) (具体见代码ok函数)来判断,这与我一位一位比较的笨方法高下立见。
3. 在判断一个状态在地图中某一行是否合法时(即地图上的'H'处不能放置大炮),将地图的每一行转换成了一个数的二进制形式,'H' 为1,'P'为0。然后用数组line[]将每一行转换成的数字存储起来。之后假设要判断状态s能否放在第i行,则判断line[i] & s是否为0。如果不为0则说明该状态一定在'H'处出现了大炮,是不合法的。
除了上面这些,我在写完之后提交了几次发现wa。
经过检查,发现了原因:
别人的代码中,在求最终结果都是进行完dp后将dp数组遍历一次,求最大值即可。
而我写的则是在dp过程中记录最大值。这思想是没错的,但并没有注意到dp的几重循环是从第二行开始的,而地图第一行的dp值我是在进行dp前单独初始化的。这样子肯定错了,因为当最大值出现在第一行中时,我就记录不到了。后来我在第一行初始化时记录下最大值,又在接下来的dp过程中记录一下,就ac了,但不如直接在dp之后遍历一遍来得简洁,就作罢了。
思路:由于每个大炮射程为2,所以如果对每一行状态压缩的话,能对它造成影响的就是上面的两行。
这里用dp[row][state1][state2]表示第row行状态为state2,第row-1行状态为state1时最多可以安放多少大炮。
则递推公式为:dp[i][K][J] = max(dp[i-1][L][K] + num[J])。其中num[J]表示状态J的二进制形式里有多少个1。
代码我是参考的别人的,觉得写得很好。
主要有一下几个地方:
1. 在判断一个数二进制形式有多少个1时,用 x & (x - 1) (具体见代码count_one函数)来判断。这种方法的时间复杂度就是x的二进制中1的个数。
假设有一个数二进制形式为1000位,其中只有一个1,则用最普通方法一位一位来数则需要计算1000次,而用该方法就是1次。
2. 在判断一个状态是否合法时(即该状态内不能有两个1距离在2以内),用x & (x << 1),x & (x << 2) (具体见代码ok函数)来判断,这与我一位一位比较的笨方法高下立见。
3. 在判断一个状态在地图中某一行是否合法时(即地图上的'H'处不能放置大炮),将地图的每一行转换成了一个数的二进制形式,'H' 为1,'P'为0。然后用数组line[]将每一行转换成的数字存储起来。之后假设要判断状态s能否放在第i行,则判断line[i] & s是否为0。如果不为0则说明该状态一定在'H'处出现了大炮,是不合法的。
除了上面这些,我在写完之后提交了几次发现wa。
经过检查,发现了原因:
别人的代码中,在求最终结果都是进行完dp后将dp数组遍历一次,求最大值即可。
而我写的则是在dp过程中记录最大值。这思想是没错的,但并没有注意到dp的几重循环是从第二行开始的,而地图第一行的dp值我是在进行dp前单独初始化的。这样子肯定错了,因为当最大值出现在第一行中时,我就记录不到了。后来我在第一行初始化时记录下最大值,又在接下来的dp过程中记录一下,就ac了,但不如直接在dp之后遍历一遍来得简洁,就作罢了。
#include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> using namespace std; int n, m, sta[62], dp[120][62][62], tot, line[120], num[62]; char map[105][13]; bool ok(int i)//判断状态i是否合法,即是否有两个1距离小于等于2 { if (i & (i<<1)) return 0; if (i & (i<<2)) return 0; return 1; } bool can(int row,int state)//判断状态state是否可以放在地图第row行 { if (state & line[row]) return 0; return 1; } int count_one(int x)//计数x的二进制状态有多少1 { int res = 0; while (x) { res++; x &= x - 1; } return res; } int getdp() { memset(dp, -1, sizeof(dp)); for (int i = 0; i < tot; i++) { num[i] = count_one(sta[i]); if (can(1, sta[i])) dp[1][0][i] = num[i]; } for (int i = 2; i <= n; i++) for (int j = 0; j < tot; j++) if (can(i, sta[j])) for (int k = 0; k < tot; k++) { if (sta[j] & sta[k]) continue; for (int l = 0; l < tot; l++) { if (sta[j] & sta[l]) continue; if (dp[i-1][l][k] == -1) continue; dp[i][k][j] = max(dp[i][k][j], dp[i-1][l][k] + num[j]); } } int res = 0; for (int i = 1; i <= n; i++) for (int j = 0; j < tot; j++) for (int k = 0; k < tot; k++) res = max(res, dp[i][j][k]); return res; } int main() { //freopen("data.in", "r", stdin); while (~scanf("%d%d",&n, &m) && n && m) { tot = 0; for (int i = 0; i < (1<<m); i++) if (ok(i)) sta[tot++] = i;//预处理所有有效状态 memset(line, 0, sizeof(line)); for (int i = 1; i <= n; i++)//将地图每一行的地形转换成二进制 { scanf("%s", map[i]); for (int j = 0; j < m; j++) if (map[i][j] == 'H') line[i] += (1<<j); } printf("%d\n", getdp()); } return 0; }
相关文章推荐
- POJ 1185 炮兵阵地(经典状态压缩dp)
- POJ 1185 炮兵阵地 经典状态压缩DP
- poj1185 炮兵阵地 经典状态压缩dp
- poj 1185 炮兵阵地(经典状态压缩dp)
- poj 1185 炮兵阵地 (状态压缩DP)
- poj 1185 炮兵阵地 (压缩状态DP)
- POJ1185炮兵阵地(DP状态压缩)
- poj 1185 炮兵阵地 状态压缩dp
- poj 1185 炮兵阵地 状态压缩dp
- POJ 1185 炮兵阵地(状态压缩dp)
- poj 1185 炮兵阵地(三维状态压缩dP)
- POJ 1185 炮兵阵地(状态压缩DP)
- POJ 1185 炮兵阵地 (状态压缩DP)
- POJ1185——炮兵阵地(状态压缩dp)
- POJ1185 炮兵阵地 状态压缩DP
- POJ 1185 炮兵阵地(状态压缩DP)
- poj 1185 炮兵阵地 状态压缩dp
- poj 1185 炮兵阵地 【状态压缩dp】
- Poj-1185 & Nyoj-81 炮兵阵地 (状态压缩动态规划经典题
- poj 1185 炮兵阵地 状态压缩dp