P2704 [NOI2001]炮兵陣地
阿新 • • 發佈:2018-11-11
題目連結: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; } }