我编写了一个matlab代码,以便找到最后一位代表here问题的人。
问题:n
人们手里拿着枪站成一个圆圈。 1次杀死2次,3次杀死4次,5次杀死6次等等(循环)直到我们只剩下一个人。谁将是最后一个活着的人。
function N = lastManStanding(n)
while length(n) ~= 1
if mod(length(n),2) == 0
for ii = 1:length(n)/2
a(ii) = [ii*2];
end
n(a) = [];
a = [];
end
if mod(length(n),2) == 1
for jj = 1:floor(length(n)/2)
b(jj) = [jj*2];
end
n(b) = [];
n = circshift(n,[0,1]);
b = [];
end
end
N = n;
这段代码基本上做的是将范围数组(1,....,n)作为输入并返回最后剩下的索引。我想知道是否存在一个封闭的形式方程来解决这个问题,或者是否可以进一步简化上述代码。
更新 找到下面的更新代码
function N = lastManStanding(n)
while length(n) ~= 1
if mod(length(n),2) == 0
n(2:2:end) = [];
else mod(length(n),2) == 1
n(2:2:end) = [];
n = circshift(n,[0,1]);
end
end
N = n;
答案 0 :(得分:4)
封闭式解决方案:
如果使用脚本为 n = 1:100绘制“幸存者”索引 i ,您将看到一个锯齿形状的函数,每个函数都会回落到1 n = 2 ^ k ,其中 k 是整数值。 这意味着在那些点 mod(n, 2 ^ k) = 0。
你可以找到2 ^ k 作为 n 2的下一个次要倍数。因此 k 是:
k = floor(log2(n));
在函数的边缘之间 n > 2 ^ k 函数以2 * mod(n, 2 ^ k)上升。由于函数的偏移量为1,因此我们可以将闭合形式的解决方案写为:
i = 2 * mod(n, 2^k) + 1;
或内联:
i = 2 * mod(n, 2.^floor(log2(n))) + 1;
情节:
<强>更新强>
这个问题也被称为约瑟夫斯问题。您可以在此处找到更一般和数学上严格的推导: https://en.wikipedia.org/wiki/Josephus_problem
答案 1 :(得分:3)
您还可以通过更加数学的方式解决此问题而无需循环:
%for n in [1,inf[
lastManStanding = mod(n,2.^floor((log(n)/log(2))))*2+1;
根据wolfie的建议,您也可以直接使用函数log2
lastManStanding = mod(n,2.^floor(log2(n)))*2+1;
函数mod可以处理向量,因此n可以是向量。
答案 2 :(得分:2)
您的更新代码已损坏,您在end
声明之前有else
声明。你的代码:
function N = lastManStanding(n)
while length(n) ~= 1
if mod(length(n),2) == 0
n(2:2:end) = [];
end % <------------------------ PROBLEM!! end before else
else mod(length(n),2) == 1 % <- PROBLEM!! condition not needed for else
n(2:2:end) = [];
n = circshift(n,[0,1]);
end
end
N = n;
可以通过注意n(2:2:end) = [];
和if
中else
是常见的来进一步简化,因此可以将其拉到外面......
function N = lastManStanding(n)
while length(n) ~= 1
n(2:2:end) = [];
if mod(length(n),2) == 1
n = circshift(n,[0,1]);
end
end
N = n;
另外,您实际上可以完全删除if
,因为mod
的输出是0
或1
,这就是您希望转换的数量!< / p>
function N = lastManStanding(n)
while length(n) ~= 1
shft = mod(length(n),2); % Have to calculate here before n gets changed
n(2:2:end) = [];
n = circshift(n,[0,shft]);
end
N = n;
评论中建议的最后一次优化是根本不使用N
。因为n
最后只是一个标量,所以使用
function n = lastManStanding(n)
while length(n) ~= 1
shft = mod(length(n),2); % Have to calculate here before n gets changed
n(2:2:end) = [];
n = circshift(n,[0,shft]);
end
请注意,我没有测试答案是否正确,但结果与您的相同。