P2704 [NOI2001]炮兵阵地

30 篇文章 1 订阅

题目链接: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;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值