问题
定义
- 我们将正整数
N
定义为数字集合在
M
进制下的可写数字(WN),如果它可以从U
的成员中使用每个成员不超过一次进行此数位记数。更严格的定义是:- 这里的
CONCAT
表示连接。 - 我们将正整数
N
定义为符号集合在
M
进制下的连续可实现数字(CAN),如果它是U
和M
的WN数字,并且N-1
是U
和M
的CAN数字(另一个定义可能是如果0 ..N
的所有数字都是U
和M
的WN,则N
是U
和M
的CAN数字)。更严格的定义是:
问题
假设我们有一组自然数S
: (我们将零视为自然数) 和自然数
M
,其中M>1
。问题是找到给定的U
和M
的最大CAN(MCAN)。给定的集合U
可能包含重复项-但每个重复项不能使用超过一次,当然(即如果U
包含{x, y, y, z}-则每个y
可以使用0或1次,因此y
总共可以使用0..2次)。同时期望U
在M
-进制下有效(即如果M=8
,则任何成员中都不能包含符号8
或9
)。并且,当然,U
的成员是数字,而不是符号(所以对于M=10
来说,11
是有效的)-否则,该问题将变得微不足道。
我的方法
我现在想到了一个简单的算法,它仅通过检查当前数字是否为CAN来进行:
- 检查是否有
0
是给定的U
和M
中的WN?转到2:我们完成了,MCAN为空 - 检查是否有
1
是给定的U
和M
中的WN?转到3:MCAN为0
- ...
因此,该算法正在尝试构建所有这些序列。我怀疑这部分可能无法改进,但也许可以?现在,如何检查数字是否为WN。这也是某种“替换暴力”的方法。我使用PHP函数实现了M=10
(事实上,由于我们处理字符串,任何其他M
都不是问题):
//$mNumber is our N, $rgNumbers is our U
function isWriteable($mNumber, $rgNumbers)
{
if(in_array((string)$mNumber, $rgNumbers=array_map('strval', $rgNumbers), true))
{
return true;
}
for($i=1; $i<=strlen((string)$mNumber); $i++)
{
foreach($rgKeys = array_keys(array_filter($rgNumbers, function($sX) use ($mNumber, $i)
{
return $sX==substr((string)$mNumber, 0, $i);
})) as $iKey)
{
$rgTemp = $rgNumbers;
unset($rgTemp[$iKey]);
if(isWriteable(substr((string)$mNumber, $i), $rgTemp))
{
return true;
}
}
}
return false;
}
-所以我们先尝试用递归写一个数字,然后检查剩余部分能否用递归写出。如果不能用递归写出,我们会尝试下一个U
成员。我认为这是可以改进的一个点。
具体细节
正如您所见,算法正在尝试构建出所有N
之前的数字,并检查它们是否为WN。但唯一的问题是-找到MCAN,因此问题是:
- 在这里使用构造算法是否过度?如果是,还有什么其他选项可供使用?
- 有更快的方法确定给定
U
和M
的数字是否为WN吗?(如果上一个问题有积极答案并且我们不构建和检查N
之前的所有数字,则此点可能没有意义。)
样例
U = {4, 1, 5, 2, 0} M = 10
则MCAN=2(无法达到3)
U = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11} M = 10
则MCAN=21(之前的都可以被达成,对于22
而言,总共没有两个2
符号)。
11>10
- 是的,但是10可以由1
和0
组合而成 - 它们存在于U
中。 - Alma Do