铺地砖|状压DP练习
2015-10-22 09:35
211 查看
有一个N*M(N<=5,M<=1000)的棋盘,现在有1*2及2*1的小木块无数个,要盖满整个棋盘,有多少种方式?答案只需要mod1,000,000,007即可。
//我也不知道这道题的来源QAQ
N和M的范围本应是相同的,但是题目给出的N的值很小,这就给我们提供了使用状压DP的思路。
假设第一列已经铺满,则第二列的情况只与第一列对它的影响有关,同理,第三列的情况也只与第二列对它的影响有关,我们可以利用二进制来表示某一列的情况,状态state表示某一列的状态,例如state=4,则此列状态为00100,用dp[i][state]表示第i列,第i-1列对它的影响为state的方案数,求每一列的方案数可以通过搜索来实现,dp[i][state]=sigma(dp[i-1][la]) la可以通过填放变为state。
代码:
//铺棋盘 //2015/10/22 #include<cstdio> #include<iostream> #include<cstdlib> #include<cmath> #include<vector> #include<cstring> #include<algorithm> #define maxn 100000000+50 #define inf 0x7fffffff #define xiao 1e-9 #define mod 1000000007 using namespace std; int dp[1005][40],n,m; void dfs(int i,int j,int state,int next) { if(j==n) { dp[i+1][next]+=dp[i][state]; dp[i+1][next]%=mod; return; }//如果枚举到了最后一行,则下一列状态为next时方案数加上此列状态为state的方案数 if(((1<<j)&state)>0) dfs(i,j+1,state,next);//如果第j行位置已被占用,直接跳过,搜索j+1行 if(((1<<j)&state)==0) dfs(i,j+1,state,next|(1<<j));//如果未被占用,尝试填放一个1*2的 if(j+1<n&&((1<<j)&state)==0&&((1<<(j+1)&state)==0)) dfs(i,j+2,state,next);//如果此位置以及下一位置都未被占用,尝试放一个2*1的 return; } int main() { cin>>n>>m; memset(dp,0,sizeof(dp)); dp[1][0]=1; for(int i=1;i<=m;++i) for(int j=0;j<(1<<n);++j) { if(dp[i][j]) dfs(i,0,j,0); } cout<<dp[m+1][0]<<endl; return 0; }
相关文章推荐
- Web缓存机制综述(HTML5缓存总结与细节释疑)
- 突然想去旅行,和陌生人一起,彼此都不了解,放开玩,想放松一下
- ZXing二维码生成在Unity3D中出错,数组超出界限的解决办法
- StarRatingBar星星切换动画《IT蓝豹》
- 阅读推荐——深入浅出Mesos
- 交互式ICP
- Android5.0后出现的新错误:fatal error 11 fault addr
- 神奇的卷积神经网络(五)总结
- SQLite创建自动增加时间的表
- IDEA 快捷键
- 大型网站架构
- NET 中的多线程
- Analyze(内存泄漏的检查)
- 在Chrome官网下载离线安装包
- LinkedList的用法小结
- 怎么写篇漂亮的research proposal,流传很广的写作指南
- android开发之蓝牙配对连接的方法
- 东北大学自动化系灵魂人物
- js闭包
- Mondrian 如何使用XML存储OLAP服务器的元数据