请问一下多诺米骨牌覆盖问题,该如何理解?

shuaiwang_01 2011-03-17 12:46:42
做算法题时,遇到一个题目(POJ 2411),意思大概就是
有一个m*n的矩形,用1*2的小矩形去填它,小矩形可以横着放竖着放,求有多少种填法?

在网上也搜了些解答,但那些人都是ACMer,他们说的太简洁了,而且代码里面的位运算也没什么解释,因而很难理解他们的核心思想。

请大家用较为清晰的方法帮我解答一下。
...全文
165 9 打赏 收藏 转发到动态 举报
写回复
用AI写文章
9 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq120848369 2011-03-21
  • 打赏
  • 举报
回复
恩,仔细思考了一下。除了我说的对1*2有递推,对于整个矩形也是递推的。先对2*N用上边的递推得到结果k。然后对M递推,分为是否有竖砖,如果N是奇数,则必需有竖砖,否则可以有也可以没有,这就是第二个递推。手机上的,明天给你写
qq120848369 2011-03-21
  • 打赏
  • 举报
回复
#include <iostream>
using namespace std;

/*
M*N
*/

int m,n,f;
bool flag=false;

int f1(int k) //2*k递推
{
if(k==1)
{
return 1;
}
else if(k==2)
{
return 2;
}
else
{
return f1(k-1)+f1(k-2);
}
}

int f2(int k) //整个矩阵递推
{
if(k==0) //mark
{
return 1;
}

if(k==1) //mark
{
if(flag)
{
return 1;
}
else
{
return 0;
}
}

if(flag) //当前排可以完全横放
{
return (f-1)*f2(k-2)+f2(k-1);
}
else //必须有竖放的
{
return f*f2(k-2);
}
}

int getResult()
{
if(m%2!=0 && n%2!=0)
{
return -1;
}

if(m%2==0)
{
f=f1(n);

if(n%2==0)
{
flag=true;
}

return f2(m);
}

if(n%2==0)
{
f=f1(m);

if(m%2==0)
{
flag=true;
}

return f2(n);
}

return -1;
}

int main()
{
cin>>m>>n;

cout<<getResult()<<endl;

return 0;
}


做了一个BUG修改,mark处
qq120848369 2011-03-21
  • 打赏
  • 举报
回复
#include <iostream>
using namespace std;

/*
M*N
*/

int m,n,f;
bool flag=false;

int f1(int k) //2*k递推
{
if(k==1)
{
return 1;
}
else if(k==2)
{
return 2;
}
else
{
return f1(k-1)+f1(k-2);
}
}

int f2(int k) //整个矩阵递推
{
if(k<=1)
{
return 1;
}

if(flag) //当前排可以完全横放
{
return (f-1)*f2(k-2)+f2(k-1);
}
else //必须有竖放的
{
return f*f2(k-2);
}
}

int getResult()
{
if(m%2!=0 && n%2!=0)
{
return -1;
}

if(m%2==0)
{
f=f1(n);

if(n%2==0)
{
flag=true;
}

return f2(m);
}

if(n%2==0)
{
f=f1(m);

if(m%2==0)
{
flag=true;
}

return f2(n);
}

return -1;
}

int main()
{
cin>>m>>n;

cout<<f1(m)<<" "<<f1(n)<<endl;
cout<<getResult()<<endl;

return 0;
}
shuaiwang_01 2011-03-21
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 qq120848369 的回复:]

C/C++ code
#include <iostream>
using namespace std;

/*
M*N
*/

int m,n,f;
bool flag=false;

int f1(int k) //2*k递推
{
if(k==1)
{
return 1;
}
else if(k==2)
{
……
[/Quote]
你这个计算有一条边边长为2的话,答案是正确的,但是计算4*11就错了。
qq120848369 2011-03-20
  • 打赏
  • 举报
回复
编程之美上的问题,对于2*M的地图,F(M)=F(M-1)+F(M-2);

如果M和N都是奇数,那么1*2的砖肯定没法覆盖。

如果M和N中有偶数,则可以沿着偶数边,切割成若干个2*M的小地图,对于一个小地图上的情况可以调用上边的递

推计算,有N/2个2*M小地图,那么就是F(M)^(N/2)种放法。

差不多就是这样了。
shuaiwang_01 2011-03-20
  • 打赏
  • 举报
回复
谢谢楼上的帮助。
test0231 2011-03-20
  • 打赏
  • 举报
回复
帮你顶一下。感觉很有趣的问题。
时间复杂度(渐近时间复杂度的严格定义,NP问题,时间复杂度的分析方法,主定理)   排序算法(平方排序算法的应用,Shell排序,快速排序,归并排序,时间复杂度下界,三种线性时间排  序,外部排序)   数论(整除,集合论,关系,素数,进位制,辗转相除,扩展的辗转相除,同余运算,解线性同余方程,中国剩余定理) 指针(链表,搜索判重,邻接表,开散列,二叉树的表示,多叉树的表示) 按位运算(and,or,xor,shl,shr,一些应用) 图论(图论模型的建立,平面图,欧拉公式与五色定理,求强连通分量,求割点和桥,欧拉回路,AOV问题,AOE问题,最小生成树的三种算法,最短路的三种算法,标号法,差分约束系统,验证二分图,Konig定理,匈牙利算法,KM算法,稳定婚姻系统,最大流算法,最小割最大流定理,最小费用最大流算法) 计算几何(平面解几及其应用,向量,点积及其应用,叉积及其应用,半平面相交,求点集的凸包,最近点对问题,凸多边形的交,离散化与扫描) 数据结构(广度优先搜索,验证括号匹配,表达式计算,递归的编译,Hash表,分段Hash,并查集,Tarjan算法,二叉堆,左偏树,二斜堆,二项堆,二叉查找树,红黑树,AVL平衡树,Treap,Splay,静态二叉查找树,2-d树,线段树,二维线段树,矩形树,Trie树,块状链表) 组合数学(排列与组合,鸽笼原理,容斥原理,递推,Fibonacci数列,Catalan数列,Stirling数,差分序列,生成函数,置换,Polya原理) 概率论(简单概率,条件概率,Bayes定理,期望值) 矩阵(矩阵的概念和运算,二分求解线性递推方程,多骨牌棋盘覆盖方案数,高斯消元) 字符串处理(KMP,后缀树,有限状态自动机,Huffman编码,简单密码学) 动态规划(单调队列,凸完全单调性,树型动规,多叉转二叉,状态压缩类动规,四边形不等式) 博奕论(Nim取子游戏,博弈树,Shannon开关游戏) 搜索(A*,ID,IDA*,随机调整,遗传算法)

69,371

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧