最长的多米诺骨牌链/序列
Longest domino chain/sequence
我需要找到最长的多米诺骨牌链,给定一组随机挑选的12个多米诺骨牌。我已经递归地生成了多米诺骨牌的所有可能性(使用0到12的面值有91种可能性)。多米诺骨牌由一块上面有两个正方形的"砖"组成:[A|b],其中0=<a、 b<=12.因此,多米诺骨牌的示例可以是[12,0]或[6,3]等。如果相邻的两半具有相同的值,则多米诺骨牌可以连接。
多米诺骨牌可以翻转以适应比赛。例如,给定[8,4],[9,4]可以翻转以使对[8,4][4,9]
以下(与此问题相关)方法可用于此类:
void flipEnds(); // Flips the domino
int getLeft() const;
int getRight() const;
bool hasBeenPlayed() const;
void setPlayed(bool value);
因此,这个问题的样本数据如下:
myDomino #0: [1 12 ]
myDomino #1: [0 5 ]
myDomino #2: [7 9 ]
myDomino #3: [2 7 ]
myDomino #4: [7 12 ]
myDomino #5: [4 8 ]
myDomino #6: [8 10 ]
myDomino #7: [3 11 ]
myDomino #8: [11 12 ]
myDomino #9: [10 11 ]
myDomino #10: [2 9 ]
myDomino #11: [2 4 ]
这更像是一道数学题,但我如何才能找到最长的多米诺骨牌链?我认为它必须递归地完成。
多米诺骨牌的序列可以表示为{#3,Y},{#4,N},{#0,Y}。。。第一个数字是你手中多米诺骨牌的数字,第二个数字是它是否翻转。我们想检查每一个可能的序列,但要尽早删除明显非法的序列。
假设您有一个函数testSequence(sequence)
,它测试序列是否有效。保留两个列表,一个是当前序列currentSeq
,另一个是尚未选择unused
的多米诺骨牌。
递归可能类似
checkAllSeq( currentSeq, unused ) {
foreach( domino in unused ) {
unused2 = unused - domino // remove domino from unused list
seq1 = currentSeq + {domino,true} // add unfliped domino to sequence to test
if( testSequence(seq1) ) {
checkAllSeq(seq1,unused2) // recurse
}
// now do it with the domino flipped
seq2 = currentSeq + {domino,false}
if( testSequence(seq2) ) {
checkAllSeq(seq2,unused2)
}
}
}
我遗漏了几件事。这只是测试所有可能的序列,对结果没有任何作用。
我认为您可以很容易地将此问题表述为树遍历,以获得强力解决方案。
树的"根"是多米诺骨牌的首选。该节点的子节点将是可以添加到其中的每个多米诺骨牌。每降低一级都会在多米诺骨牌链的长度上添加一个。
此外,请记住,每个添加的多米诺骨牌都可以添加到链的"头"或"尾",这将增加给定节点可能的子节点数量。
许多链将被缩短,因为你没有选择了——换句话说,树中的许多节点将没有子节点。这将加快您的搜索速度。
一旦这样表述,你的问题就是遍历树,找到树中最长的链。听起来像是一个很好的递归应用程序(:
请注意,对于任何可以递归解决的问题,总是可以获得迭代解决方案,反之亦然。但我同意递归更容易解决这个问题(通常是这样)。
对于任何递归问题,都必须处理三种情况:初始情况、中间情况和终止情况。在这里,最初的情况是当你没有玩多米诺骨牌时(所以你可以在任何方向上玩任何多米诺骨牌);中间的情况是当你被要求玩一个与最近的多米诺骨牌相匹配的时候;终端情况是没有多米诺骨牌可以添加到最后一个多米诺骨牌上,或者所有多米诺骨牌都玩完了。
你需要记录两个多米诺骨牌列表:一个用于当前最知名的比赛,另一个用于目前的比赛尝试。
如果你能玩完所有的多米诺骨牌,那就早点回来;否则,可能的最佳输入实际上将花费最长的时间。
这是一种幼稚的方法,它是NP难的(多米诺骨牌两端具有相同数字的可能性不会对问题产生显著影响;它只会给每条边的权重增加0.5);使用启发法可能是值得的。
无论如何,我强烈建议先对你的多米诺骨牌进行排序,如果有重复的话就出错(记住要将翻转规范化),因为重复需要一种不同的方法来解决问题。
我也需要这个,所以我对它进行了编码。这是我的解决方案,大致基于上面salix alba的伪代码:
#include <iostream>
#include <string>
using namespace std;
struct Tile
{
int val[2];
};
Tile *tiles = NULL;
int nbtiles = 0;
struct Sequence
{
int flip;
int used;
};
Sequence *seq = NULL;
int *order = NULL;
int maxlevel = 0;
int usage (char *name)
{
cerr << "usage: " << name << " start_value tile_left tile_right {tile_left tile_right} ... " << endl;
return 1;
}
int readTiles (int argc, char *argv[])
{
if ((argc & 0x1) != 0)
return (usage (argv[0]));
if (argc < 4)
return (usage (argv[0]));
nbtiles = (argc - 2) / 2;
tiles = new Tile[nbtiles];
int side = 0;
int itile = 0;
for (int i = 2; i < argc; i++)
{
tiles[itile].val[side] = atoi (argv[i]);
side = 1 - side;
if (side == 0)
{
itile++;
}
}
return 0;
}
int findLongest (int start, int level)
{
int ret = 0;
//The "if" below inefficient, but don't care, done at most nbtiles times
if (level > maxlevel)
{
cout << "new high level " << level;
for (int lev = 0; lev < level; lev++)
{
int used = seq[lev].used;
if (used) order[used] = lev;
}
for (int ind = 1; ind < level; ind++)
{
int lev = order[ind];
int flip = seq[lev].flip;
cout << " (" << tiles[lev].val[flip] << "," << tiles[lev].val[1 - flip] << ")";
}
cout << endl;
maxlevel = level;
}
for (int itile = 0; itile < nbtiles; itile++)
{
if (seq[itile].used == 0)
{
for (int flip = 0; flip < 2; flip++)
{
if (tiles[itile].val[flip] == start)
{
seq[itile].flip = flip;
seq[itile].used = level;
findLongest (tiles[itile].val[ 1 - flip], level + 1);
seq[itile].used = 0;
}
}
}
}
return ret;
}
int main (int argc, char *argv[])
{
int ret = readTiles (argc, argv);
if (ret != 0) return ret;
//for (int i = 0; i < nbtiles; i++)
//cout << tiles[i].val[0] << " " << tiles[i].val[1] << endl;
int start = atoi (argv[1]);
seq = new Sequence[nbtiles];
order = new int[nbtiles];
findLongest (start, 1);
return 0;
}
- C++boost序列化多态性问题
- 最多总和为'k'的子序列
- 序列化多晶型接口
- 具有多个值的无序列图及其查找
- 从一个文件中读取多个序列化对象
- 在C++中使用POCO和grain对多个对象进行反序列化
- 如何找到彼此朋友的大小 k(或更多)的序列?
- 对多个序列运行操作
- 了解C++中多态对象的序列化
- 使用提升序列化多态类
- 在Qt C++中序列化/解析一个文件中的多个对象
- 多米诺骨牌计划。我不知道如何将我的矢量拉到空白中以打印出来
- 找到最长的UTF-8序列,而无需打破多字节序列
- 如何使用任何编程语言组合序列中的多个图像
- C++使用多线程的无序列图填充
- C++:定义多个构造函数时的对象创建/销毁序列
- 使用 2x1 和 1x2 多米诺骨牌平铺具有禁止位置的 2xN 网格的方法数量
- 计算网格的多米诺骨牌覆盖物的数量
- C++生成多米诺骨牌的随机数
- 最长的多米诺骨牌链/序列