1. 程式人生 > >P2704 [NOI2001]炮兵陣地

P2704 [NOI2001]炮兵陣地

題目連結: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;
	}
}