题目链接:https://www.luogu.org/problemnew/show/P2704
状压DP
dp[i][j][k]在第i层,第j个状态下,上面那层为k的最大值
代码:
import java.util.*;
import java.io.*;
public class Main {
static int state[],stateLen; //表示所有可能状态,长度
static int num[]; //表示每种状态下可能拥有的个数
static int dp[][][]; //dp[i][j][k]在第i层,第j个状态下,上面那层为k的最大值
static int n,m;
static int have[]; //have表示地图状态
static StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
public static void main(String[] args) throws Exception {
init();
setState();
setDp();
System.out.println(getAns());
}
static void init() throws Exception{
n=getInt();
m=getInt();
have=new int[1500];
num=new int[1500];
//判断状态,这里地图直接取反。
for(int i=0;i<n;i++) {
String s=getString();
for(int j=0;j<m;j++) {
if(s.charAt(j)=='H')
have[i]+=1<<(m-j-1);
}
}
}
static void setState() throws Exception{
state=new int[100];
num=new int[100];
int totle=1<<m;
for(int i=0;i<totle;i++)
if(isOk(i)) {
state[stateLen++]=i;
for(int j=i;j!=0;j=j>>1)
num[stateLen-1]+=j&1;
}
}
static void setDp() {
dp=new int[105][100][100];
//第一层
for(int i=0;i<stateLen;i++)
if(isOk(have[0],i)) {
dp[0][i][0]=num[i];
}
if(n<2)
return;
//第二层
for(int i=0;i<stateLen;i++) {
if(isOk(have[1],i))
for(int j=0;j<stateLen;j++) {
if(isOk(state[i],j))
dp[1][i][j]=dp[0][j][0]+num[i];
}
}
//大于2
for(int i=2;i<n;i++) {
for(int j=0;j<stateLen;j++) {
if(isOk(have[i],j)) {
for(int k=0;k<stateLen;k++) {
if(isOk(state[j],k)) {
for(int l=0;l<stateLen;l++) {
if(isOk(state[j],l)) {
dp[i][j][k]=Math.max(dp[i][j][k],dp[i-1][k][l]);
}
}
dp[i][j][k]+=num[j];
}
}
}
}
}
}
static int getAns() {
int ans=0;
for(int j=0;j<stateLen;j++)
for(int k=0;k<stateLen;k++)
ans=Math.max(ans,dp[n-1][j][k]);
return ans;
}
//判断这个状态是否可行
static boolean isOk(int x) {
return (x&(x<<1))==0&&(x&(x<<2))==0;
}
//判断上一层的状态是否和这一层冲突
static boolean isOk(int a,int b) {
return (a&state[b])==0;
}
static int getInt() throws Exception{
in.nextToken();
return (int) in.nval;
}
static String getString() throws Exception{
in.nextToken();
return in.sval;
}
}