Poj 1185 java实现--状态压缩
这个题目和之前做过的Corn Fields,可以说一模一样.....关于状态压缩的动态规划。
Corn Fields说的时不能上下左右相邻,这个变成不能上下左右2个跨度的相邻。
所以基本思路相同:
1.压缩行的状态,将每行的可以选择的情况视为二进制,进而转为十进制去执行判断
2.记录每行的状态,进行比较。因为不能和上一行和上上一行相邻,所以仍旧使用[(状态1&状态2) == 0]来判断当前行是否合法。
3.Corn Fields只需要和上一行进行判断,所以可以枚举每种状态,直接讨论当前行能否放置,当前状态是否符合1不相邻。二维数组开辟dp[行][1<<列]大小也不会很多,但是本题目需要和前两行判断,所以数组变成三维
dp[行][1<<列][1<<列],直接记录会比较大。这里先对每行所有状态进行一次过滤,取出符合 相邻两位,相邻三位没有相同的1的情况,使用索引标记情况,数组值为当前情况对应的状态。最后可以算出符合基本情况的状态只有60多中,所以三维数组可以开辟为dp[行][70][70]大小。
4.执行比较操作,排除不符合情况的状态,这个和Cron Fields相同。
a.当前行放置是否符合地形规则
b.当前行放置是否和上一行不相邻
c.当前行放置是否和上上一行不相邻
5.统计最后一行的结果即可。
dp数组的含义:
在第三步中,使用了一个数组,就叫做possibleStatus[]吧,记录了所有的可能状态。
dp[i][j][k]代表在第i行,并且当前行状态为possibleStatus[k],并且上一行状态为possibleStatus[j]的情况下,可以放置炮兵的最大数量。
所以状态转移方程:
i--行,j--当前行possibleStatus状态的索引,p--上一行possibleStatus状态的索引,k--上上一行能够放置的possibleStatus状态的索引。
所以
当前行的状态:dp[i][p][k]
上一行的状态:dp[i-1][k][p]
dp[i][p][j] = Math.max(dp[i][p][j],dp[i-1][k][p]+oneNumCnt(possibleStatus[j]))
oneNumCnt(possibleStatus[j])就是当前放置状态possibleStatus[j]中可放炮兵的数量---就是1的数量。
java代码如下:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
static char[][] info;
static int[][] transInfo;
static int[] possibleStatus;
static int possibleStatusCnt;
static int[][][] dp;
static int[] rowInitPosition;
static int n,m;
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
n = Integer.parseInt(st.nextToken());
m = Integer.parseInt(st.nextToken());
info = new char[n][m];
transInfo = new int[n][m];
possibleStatus = new int[100];
dp = new int[n][100][100];
rowInitPosition = new int[n];
initDp();
initPossibleStatus();
char[] inputCharArray;
for(int i = 0;i<info.length;i++){
inputCharArray = br.readLine().toCharArray();
info[i] = inputCharArray;
for(int j = 0;j<info[0].length;j++){
transInfo[i][j] = inputCharArray[j] == 'P'?1:0;
rowInitPosition[i] += transInfo[i][j]*(1<<(info[0].length-1-j));
}
}
for(int i = 0;i<possibleStatusCnt;i++){
if((possibleStatus[i]&rowInitPosition[0]) != possibleStatus[i]){
continue;
}
dp[0][0][i] = getNumberBinaryOneCnt(possibleStatus[i]);
}
for(int i=1;i<n;i++){
for(int j = 0;j<possibleStatusCnt;j++){
//current row
if((possibleStatus[j]&rowInitPosition[i]) != possibleStatus[j]){
continue;
}
for(int k = 0;k<possibleStatusCnt;k++){
//current-1 row
if(is2RowPositionNotOk(possibleStatus[j], possibleStatus[k])){
continue;
}
for(int p = 0;p<possibleStatusCnt;p++){
//current-2 row
if(is2RowPositionNotOk(possibleStatus[j], possibleStatus[p])){
continue;
}
if(dp[i-1][k][p] == -1){
continue;
}
dp[i][p][j] = Math.max(dp[i][p][j],dp[i-1][k][p]+getNumberBinaryOneCnt(possibleStatus[j]));
}
}
}
}
int result = 0;
for(int i = 0;i<n;i++){
for(int j = 0;j<possibleStatusCnt;j++){
for(int k = 0;k<possibleStatusCnt;k++){
result = Math.max(result,dp[i][j][k]);
}
}
}
System.out.println(result);
}
private static void initPossibleStatus(){
possibleStatusCnt = 0;
for(int i = 0;i<(1<<m);i++){
if((i&(i<<1)) == 0 && (i&(i<<2)) == 0){
possibleStatus[possibleStatusCnt] = i;
possibleStatusCnt++;
}
}
}
private static void initDp(){
for (int[][] ints : dp) {
for (int[] anInt : ints) {
Arrays.fill(anInt, -1);
}
}
}
private static boolean is2RowPositionNotOk(int x, int y){
return (x & y) != 0;
}
private static int getNumberBinaryOneCnt(int num){
int cnt = 0;
while (num != 0){
num = (num&(num-1));
cnt++;
}
return cnt;
}
}