poj3254 状态压缩DP
来源:互联网 发布:python 算法导论 编辑:程序博客网 时间:2024/05/16 18:34
链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3254
全程精讲
农夫有一块地,被划分为m行n列大小相等的格子,其中一些格子是可以放牧的(用1标记),农夫可以在这些格子里放牛,其他格子则不能放牛(用0标记),并且要求不可以使相邻格子都有牛。求方案数
#include <cstdio>#include <cstring>using namespace std;#define mod 100000000int M,N,top = 0;//top表示每行最多的状态数int state[600],num[110]; //state存放每行所有的可行状态(即没有相邻的状态int dp[20][600];//dp[i][j]:对于前i行数据,每行有前j种可能状态时的解//~8:应该表示 对于前i行数据,当前i行用j状态时的解(因为状态转移方程--)int cur[20];//cur[i]表示的是第i行整行的情况//、、、果然还是一步步亲自调试才能明白inline bool ok(int x){//判断状态x是否可行(~1其实是当前行判断相邻是否有同1(x<<1:把x的二进制末尾补0右移一位)) if(x&x<<1)return false;//若存在相邻两个格子都为1,则该状态不可行 return true;}void init(){//遍历所有可能的状态 top = 0; int total = 1 << N; //遍历状态的上界 for(int i = 0; i < total; ++i){ if(ok(i))state[++top] = i;//保存当前行的可行状态——不一定符号题目的可以种菜 }}inline bool fit(int x,int k){ //判断状态x 与第k行的"实际"状态的逆是否有‘重合’ if(x&cur[k])return false; //若有重合(即x不符合要求)(~2其实:把菜种在不可种的地方了,因为x是表可种) return true; //若没有,则可行}/*line34-36(其实我不知道这在说什么--也不打算知道)此处,注意要用相反存储的数据来判断,因为若10101001是一种可行状态,则可知101001也可行(是前者的一部分)这时x即为10101001,cur[k]为10110,x&cur[k]=0,即符合条件*/int main(){ while(scanf("%d%d",&M,&N)!= EOF){ init(); memset(dp,0,sizeof(dp)); for(int i = 1; i <= M; ++i){ cur[i] = 0; int num; for(int j = 1; j <= N; ++j){ //输入时就要按位来存储,cur[i]表示的是第i行整行的情况,每次改变该数字的二进制表示的一位 scanf("%d",&num); //表示第i行第j列的情况(0或1) if(num == 0) //若该格为0 cur[i] +=(1<<(N-j)); //则将该位置为1(注意要以相反方式存储,原因参看line34-36//(~3即把"不可种"菜的二进制存成10进制,在fit()里用来判是否把菜种在不可种的地方了) } } for(int i = 1;i <= top;i++){//~~dp初始化 if(fit(state[i],1)){ //判断所有可能状态与第一行的实际状态的逆("不可种"菜)是否有重合 dp[1][i] = 1; //若第1行的状态与第i种可行状态吻合,则dp[1][i]记为1 } } /* 状态转移过程中,dp[i][k] =Sigma dp[i-1][j] (j为符合条件的所有状态) */ for(int i = 2; i <= M; ++i){ //i索引第2行到第M行 for(int k = 1; k <= top; ++k){ //该循环针对所有可能的状态,找出一组与第i行相符的state[k] if(!fit(state[k],i))continue; //判断是否符合第i行实际情况//~4给i选一个状态 for(int j = 1; j <= top ;++j){ //找到state[k]后,再找一组与第i-1行符合,且与第i行(state[])不冲突的状态state[j] if(!fit(state[j],i-1))continue; //判断是否符合第i-1行实际情况//~5给i-1选一个状态 if(state[k]&state[j])continue; //判断是否与第i行冲突//~6判断两个选中的相邻行状态是否有冲突(相邻格子种菜) dp[i][k] = (dp[i][k] +dp[i-1][j])%mod; //若以上皆可通过,则将'j'累加到‘k'上//~7.要是转移失败就说明该状态挂了,不过直觉(稍微想)不会全挂...//~9.这个转移方程还得多注意~~(不怎么偏向于DP(灵活flexible)but 理解) } } } int ans = 0; for(int i = 1; i <= top; ++i){ //累加最后一行所有可能状态的值,即得最终结果!!!泥马写注释累死我了终于写完了! ans = (ans + dp[M][i])%mod; } printf("%d\n",ans); }}
0 0
- Poj3254 状态压缩DP
- poj3254 状态压缩dp
- poj3254 状态压缩dp
- POJ3254(DP状态压缩)
- poj3254 状态压缩DP
- poj3254 状态压缩dp
- poj3254(状态压缩dp)
- poj3254(状态压缩dp)
- POJ3254 状态压缩+dp
- poj3254 状态压缩dp
- poj3254 poj1185 状态压缩DP
- poj3254--Fields+状态压缩dp
- poj3254(状态压缩dp)
- 状态压缩DP POJ3254 && POJ1185
- POJ3254(状态压缩DP)
- poj3254(状态压缩DP)
- poj3254 Corn Fields----dp状态压缩
- poj3254 - Corn Fields(状态压缩dp)
- 2015C++第二周,任务一:输入100-999之间的水仙花数,153=13+53+33。
- UVa 340 Master-Mind Hints
- 面向对象,继承,父类子类,继承中构造函数问题,对象初始化器
- 依赖倒转原则
- HTTP协议
- poj3254 状态压缩DP
- jQuery实现复选框 全选、反选、全不选
- 2015C++第二周,任务二:输出9*9乘法表
- 基于storm的实时GPS数据客流特征分析系统 源码分析之(一):GPSReceiverSpout
- 2015C++第二周,任务三:输出带字母的图形,A,AB,ABC,ABCD,ABCDE
- xmpp错误日志集锦
- java调用webservice的四种方式
- 100条经典语录
- 2015C++第二周,任务七:以不同的形式输出日期,月份以英文显示,涉及类,构造函数等等,并限定月份只有12个月,日期与实际情况相同,如果输入错误则显示为0.