状压dp套路总结

1.创建变量,状态转移数组dp,行内合法状态数组state,记录行内合法状态的某种属性的数组num,记录状态数量的count,原始行数组row,等
2.写判断合法的函数。判断行内合法ok(int sta),判断两行之间合法fit(int sta1,int sta2),等
3.写main函数:填充row(注意有时会把原图的01代码取反,以方便使用ok函数),填充state和num,初始化dp的起始值,开始利用fit函数进行状态转移,得出答案。
注意:1.根据题意,有时当前行能否到达某个状态取决于其上不止一行的状态。如果与前两行有关,则开三维数组,而不是只与前一行有关时开的二维数组。
2.状态数太多数组容易溢出,如果不好判断,可以把MN最大值输入后让程序输出count判断。
3.boolean类型函数注意感叹号= =

poj1185 ac代码

package algorithm;

import java.util.Scanner;

public class test{
	public static int maxm=70;
	public static 
	int dp[][][]=new int[110][maxm][maxm],
	state[]=new int[maxm],
	num[]=new int[maxm],
	row[]=new int[110];
	public static boolean ok(int sta){//行内合法		
			int k=sta;
			if(((sta<<1)&k)==0&&((sta<<2)&k)==0){
				return true;
			}
		return false;
	}
	public static boolean fit(int sta1,int sta2) {//两行之间合法
		if((sta1&sta2)==0) {
			return true;
		}
		return false;
	}
	public static void main(String args[]) {
		Scanner sc=new Scanner(System.in);
		int N,M;
		N=sc.nextInt();
		M=sc.nextInt();
		char[] tmp;
		for(int i=0;i<N;i++) {
			tmp=sc.next().toCharArray();
			for(int j=0;j<M;j++){
				if(tmp[j]=='H') {
					row[i]+=(1<<(M-j-1));
				}
			}
		}
		
		int count=0;
		int t=0;
		for(int i=0;i<1<<M;i++) {
			if(ok(i)) {
				state[count]=i;
				t=i;
				int sum=0;
				while(t>0) {
					if((t&1)==1) {
						sum++;
					}
					t>>=1;
				}
				num[count++]=sum;

			}
		}
		
		System.out.println(count);
		//System.out.println("?");
		for(int i=0;i<count;i++) {
			if(!fit(row[0],state[i]))continue;
			dp[0][i][0]=num[i];
			
		}
		for(int i=0; i<count; i++) //接着初始化dp[1][i][j],即第2行的情况
	    {
		        if(!fit(state[i],row[1])) continue;
		        for(int j=0; j<count; j++) //枚举第1行的状态
		        {
		            if(!fit(state[j],row[0])) continue;
		            if(!fit(state[i],state[j])) continue;
		            dp[1][i][j]=Math.max(dp[1][i][j] , dp[0][j][0]+num[i]);
		            //状态转移方程
		            //System.out.println(dp[1][i][j]);
		        }
		 }

			for(int i=2;i<N;i++) {
			for(int k=0;k<count;k++) {
				if(!fit(row[i],state[k]))continue;
				for(int kk=0;kk<count;kk++) {
					if(!fit(row[i-1],state[kk]))continue;
					for(int kkk=0;kkk<count;kkk++) {
						if(!fit(row[i-2],state[kkk]))continue;
						if(fit(state[k],state[kk])&&fit(state[k],state[kkk])&&fit(state[kk],state[kkk])) {
							dp[i][k][kk]=Math.max(dp[i][k][kk], dp[i-1][kk][kkk]+num[k]);
						}
					}
				}
			}
		}
		int ans=0;
		for(int i=0;i<count;i++) {
			for(int j=0;j<count;j++) {
				ans=Math.max(ans, dp[N-1][i][j]);
			}
		}
		System.out.println(ans);
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值