POJ3254:状态DP入门级理解
来源:互联网 发布:乾坤量能指标源码 编辑:程序博客网 时间:2024/06/01 22:36
状态DP与二进制及位运算密切相关。
在这道题中,对于 一行0或1 所表示的状态,我们就可以把它们当作一个数的二进制,而它们所代表的“数”,即是表示这一行的状态。
比如(111) 就可以用 一个数 7 来表示 这一行的状态
那么接下来就要去判断 我们安排的装态 是否合法,由题意,只能在“1”上放牧,而且任意两只牛相邻是不合法的,
那么要考虑的主要有三个方面:
1: 一行安排的状态,要与这一行实际状态相容,即只能在“1”上放牧;
设该行实际状态为 i ,我们安排的状态为 j,
则合法状态满足 j & ( ~i ) == 0
理解:
将 i 取反再与 j 相与,结果为零,
如果 j 在某一位上为0,显然是合法的;如果为1,则 ~i 对应位置上必为0才能使最终结果为零;
而此时i 实际对应位== 1; 可以放牧,与 j 不冲突。。。(位运算好晕。。。)
2: 安排的状态本身左右相斥,即不能同时为1;
对于安排的状态j, 满足 j&(j<<1)==0 即可,比较简单,自己想想
3.安排的状态上下相斥;(而且当前行状态仅与上一行相关,而与其他行无关,即无后效性)
对于上一行的状态 k, 本行的状态 j,(假设它们已与实际状态相容)
满足 j & k == 0 即可;(自己推)
状态数目 的最大值为 1<<2^(M+1); 但实际上 满足条件2 的的状体就很少了,(cnt==614);
可以将它们用一个state[]数组先记录下来,循环时遍历这些合法状态即可。。。
当然,每一行的实际状态也要用map_r_state[]数组记录下来 (数组名字自己取。。。。)
dp[i][j] 表示第i行状态为state[j]时 的方案数 最终结果将dp[M][j], j={0,1,,,cnt-1};遍历相加即可
贴代码:
#include<iostream>#include<cstring>using namespace std;const int MOD = 100000000;const int MAXN = (1<<13)+5;int state[MAXN]; //实际合法状态会很少//当前状态是否合法(左右相容)//记录合法状态int cnt = 0;void state_is_legal(){ for(int j=0; j<MAXN; ++j) if( !(j&(j<<1)) ) //j&(j<<1))==0 state[cnt++] = j; //只要记录可行状态就好了}//是否符合实际情况bool r_and_v_is_legal(int n, int j){ if( !(j&(~n)) ) return true; else return false;}//上下两行状态是否相容bool l_and_n_is_legal(int j, int k){ if( !(j&k) ) return true; return false;}int main(){ memset(state,0,sizeof(state)); state_is_legal(); //cout<<"cnt "<<cnt<<endl; int M,N; while(cin>>M>>N) { int map[M+1][N+1]; int map_r_state[M+1]; memset(map_r_state,0,sizeof(map_r_state)); for(int i=1; i<=M; ++i) for(int j=1; j<=N; ++j) { cin>>map[i][j]; if(map[i][j]) map_r_state[i] += (1<<(N-j)); //注意下标,这里是从1开始 } int dp[M+1][MAXN]; memset(dp,0,sizeof(dp)); //初始化第一行 for(int j=0; j<cnt; ++j) if(r_and_v_is_legal(map_r_state[1],state[j])) dp[1][j] = 1; for(int i=2; i<=M; ++i) for(int j=0; j<cnt; ++j) { if(r_and_v_is_legal(map_r_state[i],state[j])) { for(int k=0; k<cnt; ++k) if(r_and_v_is_legal(map_r_state[i-1],state[k])) { if(l_and_n_is_legal(state[j],state[k])) dp[i][j] += dp[i-1][k]; //直接用j表示第j个合法状态 } } } int ans = 0; for(int j=0; j<cnt; ++j) ans = (ans+dp[M][j])%MOD; cout<<ans<<endl; }return 0;}
- POJ3254:状态DP入门级理解
- 【状态压缩DP】【POJ3254】【POJ1185】 入门题
- 状态压缩dp入门题 poj3254
- Poj3254 状态压缩DP
- poj3254 状态压缩dp
- poj3254 状态压缩dp
- POJ3254(DP状态压缩)
- poj3254 状态压缩DP
- poj3254 状态压缩dp
- poj3254(状态压缩dp)
- poj3254(状态压缩dp)
- POJ3254 状态压缩+dp
- poj3254 状态压缩dp
- 状态压缩dp入门 (poj3254 Corn Fields)
- POJ3254 状压DP入门
- POJ3254 状压dp入门
- poj3254 poj1185 状态压缩DP
- POJ3254 Corn Fields(状态DP)
- 关于mysql的安装
- golang之cgo---类型转换小试牛刀之C结构体和go结构体转换
- JVM垃圾收集算法的大概思想及其发展
- 【译】如何使用Android MediaStore裁剪大图片
- 云计算的三种服务模式:IaaS,PaaS和SaaS
- POJ3254:状态DP入门级理解
- 物理、化学实验仪器与设备
- 【spring 3】AOP:静态代理
- Android App的设计架构:MVC,MVP,MVVM与架构经验谈
- artTemplate学习
- 用Swift在导航栏上“镶嵌”一个搜索框
- Android 导入项目时遇到的JNI和NDK问题
- JSP基础概要
- 模块对应 widget