POJ 3254 Corn Fields 状态压缩dp入门

原文:http://blog.csdn.net/y990041769/article/details/24658419

在原文基础上,加上自己的理解

状态压缩dp入门

1、二进制的移动知识基础:

#include <cstdio>
int main()
{
	int k=5;
	printf("%d\n", 1<<k);// 1 向左移动k位 100000,2^5 32
	printf("%d\n", 1>>k);// 1 向右移动k位 0.00001,为0 
	printf("%d\n", k<<1);// k 向左移动1位 101 -> 1010 即k*2=10
	printf("%d\n", k>>1);// k 向右移动1位 101 -> 10.1 即k/2=2
	return 0;
}

 2、& 的妙用

同为1 才为1,不然就是0,

很巧妙的相错开来


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std; 
const int N=15;
const int M=1<<N;//10000000000000
const int mod = 100000000;
int st[M],mp[M];
int dp[N][M];//表示dp[i][j] 在i行 状态为j时 放牛的种数 
int jud1(int x){
	//相邻是否一样  
	return (x&(x<<1));
}
int jud2(int i,int x){
	return (mp[i]&st[x]);
}
int main()
{
	int n,m,x;
	while(~scanf("%d%d",&n,&m)){
		memset(st,0,sizeof(st));
		memset(mp,0,sizeof(mp));
		memset(dp,0,sizeof(dp));
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				scanf("%d",&x);
				if(x==0)
				//第i行的土地状况 可以累加出来 
				//而且这个土地情况 是 与真实的是相反的 
					mp[i]=mp[i]+(1<<(j-1)); 
			}
		}
		int k=0;
		//枚举m位 不同的0,1情况
		//只有相邻不同的数,左移一位相互交错,数值为0 
		//st[] 存每一行相互交错的情况 ,总交错状态数为 k 
		for(int tm=0;tm<(1<<m);tm++){
			if(  !jud1(tm)  )
				st[k++]=tm;
		}
		for(int j=0;j<k;j++){
			// 找出与第一行土地 状态为j ,且与土地交错的
			// 那么初始化为1 
			if( !jud2(1,j) )
				dp[1][j]=1;
		}
		for(int i=2;i<=n;i++){                 //枚举行数 
			for(int j=0;j<k;j++){              //枚举上一行的状态数 
			
				//一:第i行状态j 与 第i行土地交错
				if(jud2(i,j))
					continue;
				for(int f=0;f<k;f++){          //枚举下一行的状态数
				 
				//二:与第i行的上一行的土地也要交错  
					if(jud2(i-1,f))
						continue;
						
				//三:上一行状态j 和这一行状态f 也要交错 
					if(!(st[j]&st[f]))
						dp[i][j]+=dp[i-1][f];
				}
			}
		}
		//dp[最后一行][不同方案] 总值累加起来,就是结果   
		int ans=0;
		for(int j=0;j<k;j++){
			ans+=dp[n][j];
			ans%=mod;
		}
		printf("%d\n",ans);
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值