Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 17597 | Accepted: 6752 |
Description
Input
Output
Sample Input
5 4 PHPP PPHH PPPP PHPP PHHP
Sample Output
6
Source
【题目大意】类似于上面一道题,一个方格组成的矩阵,每个方格可以放大炮用0表示,不可以放大炮用1表示(原题用字母),让放最多的大炮,大炮与大炮间不会互相攻击。
【分析】这道题与上一题的不同之处在于,他需要保存上一层的状态以为对应的上上层的状态,因此需要一个三维的数组来保存数据的dp[][][],第一维表示层数,第二维表示当前层的状态的下标,第三维,表示上一层的状态的下标;下标与状态值得对应关系存放在数组goodForPut[]中;
【状态表示】dp[i][j][k] 表示第j行状态为j,且上一层状态为k的情况下最大炮兵个数。
【状态转移方程】dp[i][j][k] =max(dp[i][j][k],dp[i-1][m][j] +num[goodForPut[m]]); num[i]为i状态中1的个数
java代码
import java.io.BufferedInputStream; import java.util.Arrays; import java.util.Scanner; import org.omg.CosNaming.IstringHelper; public class Main { // 存放的是大炮的总数 // 三维数组,第一维表示层数,第二维表示当前层的状态的下标,第三维,表示上一层的状态的下标; //下标与状态值得对应关系存放在goodForPut中; private int dp[][][]; private int isOk[]; private int goodForPut[]; private int goodCount; private int allStatusCount; public Main(int M, int N) { allStatusCount = 1 << N; // 需要保存两层状态 // 值为当前最大的大炮的数量 goodForPut = new int[(1 << N)]; isOk = new int[M]; Arrays.fill(goodForPut, 0); } public static void main(String[] args) { // TODO Auto-generated method stub Scanner cin = new Scanner(new BufferedInputStream(System.in)); int M, N; M = cin.nextInt(); N = cin.nextInt(); Main ma = new Main(M, N); String str; int bit; for (int i = 0; i < M; i++) { bit = 0; str = cin.next().trim(); for (int j = 0; j < N; j++) { bit = (bit << 1); // P 可以放大炮,用1表示,H不能放大炮,用0表示 if (str.charAt(j) == ‘P‘) { bit = bit | 1; } } ma.isOk[i] = bit; } System.out.println(ma.getMostCount()); } private int getMostCount() { // TODO Auto-generated method stub prepareIt(); //显然0下标对应的是0状态 dp[0][0][0] = 0; int max = 0; // 从零层开始, for (int i = 1; i < isOk.length+1; i++) { for (int j = 0; j < goodCount; j++) { for (int m = 0; m < goodCount; m++) { if (dp[i - 1][j][m] == -1) { continue; } for (int k = 0; k < goodCount; k++) { // 判断是否是可以放大炮的哈 if ((goodForPut[k] & isOk[i - 1]) == goodForPut[k]) { // 与前两行比较; // 与上一层的状态比较, if ((goodForPut[k] & goodForPut[j]) == 0) { // 上上一层的状态; if ((goodForPut[k] & goodForPut[m]) == 0) { dp[i][k][j] = Math.max( dp[i][k][j], dp[i - 1][j][m] + num(goodForPut[k])); if(i == isOk.length){ max = Math.max(max, dp[i][k][j]); } } } } } } } } return max; } private int num(int x) { // TODO Auto-generated method stub // 获取1的个数 int cnt = 0; while (x != 0) { cnt++; x &= (x - 1); } return cnt; } private void prepareIt() { // TODO Auto-generated method stub int count = 0; int max = 0; // 建立下标与状态的对应关系 for (int i = 0; i < allStatusCount; i++) { if ((i & (i << 1)) == 0) { if ((i & (i << 2)) == 0) { goodForPut[count] = i; max = Math.max(max, i); count++; } } } goodCount = count; dp = new int[isOk.length + 1][goodCount][goodCount]; for (int i = 0; i < dp.length; i++) { for (int j = 0; j < goodCount; j++) { Arrays.fill(dp[i][j], -1); } } } }
状态压缩DP-炮兵阵地(POJ 1185),布布扣,bubuko.com
原文:http://blog.csdn.net/haizi8888/article/details/23883377