用Python解谜
我有一个难题,我想用Python解决它 谜题: 一个商人有一个40公斤的重量,他用在他的商店里。有一次,它掉了下来 从他手上摔下来,摔成4块。但令人惊讶的是,现在他 可称量1 kg至40 kg之间的任何重量 这四件 所以问题是,这4件衣服的重量是多少 现在我想用Python解决这个问题 我从拼图中得到的唯一限制是4块的总和是40。有了它,我可以过滤所有4个值的总和为40的集合用Python解谜,python,permutation,combinations,puzzle,itertools,Python,Permutation,Combinations,Puzzle,Itertools,我有一个难题,我想用Python解决它 谜题: 一个商人有一个40公斤的重量,他用在他的商店里。有一次,它掉了下来 从他手上摔下来,摔成4块。但令人惊讶的是,现在他 可称量1 kg至40 kg之间的任何重量 这四件 所以问题是,这4件衣服的重量是多少 现在我想用Python解决这个问题 我从拼图中得到的唯一限制是4块的总和是40。有了它,我可以过滤所有4个值的总和为40的集合 import itertools as it weight = 40 full = range(1,41) comb
import itertools as it
weight = 40
full = range(1,41)
comb = [x for x in it.combinations(full,4) if sum(x)==40]
梳子长度=297
现在我需要检查comb
中的每一组值,并尝试所有操作的组合
例如,如果(a,b,c,d)
是comb
中的第一组值,我需要检查a,b,c,d,a+b,a-b
我尝试了很多,但我仍停留在这个阶段,即如何检查所有这些计算组合到每组4个值
问题:
1) 我想我需要得到一个列表,列出所有可能的[a,b,c,d]和[+,-]
组合
2) 有没有人有更好的想法,告诉我如何从这里开始
另外,我想完全不用任何外部库的帮助,只需要使用python的标准库
编辑:抱歉,信息太晚了。它的答案是(1,3,9,27),这是我几年前发现的。我已经核实了答案
编辑:目前,fraxel
的答案在时间=0.16毫秒时运行良好。更好更快的方法总是受欢迎的
问候
ARK这是一个强力itertools解决方案:
import itertools as it
def merchant_puzzle(weight, pieces):
full = range(1, weight+1)
all_nums = set(full)
comb = [x for x in it.combinations(full, pieces) if sum(x)==weight]
funcs = (lambda x: 0, lambda x: x, lambda x: -x)
for c in comb:
sums = set()
for fmap in it.product(funcs, repeat=pieces):
s = sum(f(x) for x, f in zip(c, fmap))
if s > 0:
sums.add(s)
if sums == all_nums:
return c
>>> merchant_puzzle(40, 4)
(1, 3, 9, 27)
要了解它的工作原理,请查看,这是同一算法的实现。您很接近,非常接近:)
既然这是一个你想解决的难题,我就给你一些提示。本部分:
如果(a,b,c,d)是comb中的第一组值,我需要检查
a、 b,c,d,a+b,a-b,……a+b+c-d,a-b+c+d。。。。。。。。等等
考虑一下:每个重量可以放在一个秤上,或者放在另一个秤上,或者两者都不放。因此,对于a
的情况,这可以表示为[a,-a,0]
。其他三个也一样。现在,您需要所有可能的配对,每个权重都有这3种可能(提示:itertools.product
)。然后,一个配对的可能度量(比如:(a,-b,c,0)
)仅仅是这些(a-b+c+0
)的总和
剩下的只是检查你是否能“测量”所有需要的重量<代码>设置
可能在这里派上用场
PS:正如评论中所述,对于一般情况,可能没有必要区分这些划分的权重(对于这个问题是这样的)。你可以重新考虑一下itertools.compositions
我用蛮力逼出了第二部分
如果不想看到答案,请不要单击此按钮。显然,如果我更擅长排列,这将需要更少的剪切/粘贴搜索/替换:
前面的一个问题: 我们知道
a*a+b*b+c*c+d*d=x
对于0到40之间的所有x
,而a、b、c、d
仅限于-1、0、1
。显然A+B+C+D=40
。下一种情况是x=39
,因此很明显,最小的移动是移除一个元素(这是唯一可能导致与39成功平衡的移动):
A+B+C=39
,因此根据需要D=1
下一步:
A+B+C-D=38
下一步:
A+B+D=37
,所以C=3
然后:
A+B=36
然后:
A+B-D=35
A+B-C+D=34
A+B-C=33
A+B-C-D=32
A+C+D=31
,所以A=9
因此B=27
因此权重是1,3,9,27
事实上,这可以从它们都必须是3的倍数这一事实立即推断出来
有趣的更新:
下面是一些python代码,用于为将跨越整个空间的任何下降权重找到一组最小权重:
def find_weights(W):
weights = []
i = 0
while sum(weights) < W:
weights.append(3 ** i)
i += 1
weights.pop()
weights.append(W - sum(weights))
return weights
print find_weights(40)
#output:
[1, 3, 9, 27]
我将三元计数从0到9放在旁边,以说明我们有效地处于三元数系统中(以3为基数)。我们的解决方案始终可以写成:
3**0 + 3**1 +3**2 +...+ 3**N >= Weight
对于最小N,这是正确的。最小解决方案将始终采用这种形式
此外,我们可以轻松解决大重量的问题,并找到跨越空间的最小件数:
def find_weights(W):
weights = []
i = 0
while sum(weights) < W:
weights.append(3 ** i)
i += 1
weights.pop()
weights.append(W - sum(weights))
return weights
print find_weights(40)
#output:
[1, 3, 9, 27]
一个人把一个已知的砝码掉下来,它就会碎裂成碎片。他的新砝码允许他称任何重量到W。有多少个砝码,它们是什么?
#what if the dropped weight was a million Kg:
print find_weights(1000000)
#output:
[1, 3, 9, 27, 81, 243, 729, 2187, 6561, 19683, 59049, 177147, 531441, 202839]
尝试对较大重量和未知数量的碎片使用排列 我不知道Python语法,但也许你可以解码这个Scala代码;从第二个for循环开始:
def setTo40 (a: Int, b: Int, c: Int, d: Int) = {
val vec = for (
fa <- List (0, 1, -1);
fb <- List (0, 1, -1);
fc <- List (0, 1, -1);
fd <- List (0, 1, -1);
prod = fa * a + fb * b + fc * c + fd * d;
if (prod > 0)
) yield (prod)
vec.toSet
}
for (a <- (1 to 9);
b <- (a to 14);
c <- (b to 20);
d = 40-(a+b+c)
if (d > 0)) {
if (setTo40 (a, b, c, d).size > 39)
println (a + " " + b + " " + c + " " + d)
}
def设置为40(a:Int,b:Int,c:Int,d:Int)={
val vec=用于(
fa使用砝码[2,5,15,18],您也可以测量1到40kg之间的所有物体,尽管其中一些物体需要间接测量。例如,要测量一个重量为39kg的物体,您首先将其与40kg进行比较,然后天平将悬挂在40kg一侧(因为39<40),但如果你去掉2kg的重量,它会垂向另一侧(因为39>38),因此你可以得出物体重量为39kg的结论
更有趣的是,使用权重[2,5,15,45],您可以测量高达67kg的所有对象。如果任何人不想导入库来导入组合/烫发,这将生成所有可能的四步移动策略
# generates permutations of repeated values
def permutationsWithRepeats(n, v):
perms = []
value = [0] * n
N = n - 1
i = n - 1
while i > -1:
perms.append(list(value))
if value[N] < v:
value[N] += 1
else:
while (i > -1) and (value[i] == v):
value[i] = 0
i -= 1
if i > -1:
value[i] += 1
i = N
return perms
# generates the all possible permutations of 4 ternary moves
def strategy():
move = ['-', '0', '+']
perms = permutationsWithRepeats(4, 2)
for i in range(len(perms)):
s = ''
for j in range(4):
s += move[perms[i][j]]
print s
# execute
strategy()
#生成重复值的排列
def置换SWI
#!/usr/bin/env python3
weight = 40
parts = 4
part=[0] * parts
def test_solution(p, weight,show_result=False):
cv=[0,0,0,0]
for check_weight in range(1,weight+1):
sum_ok = False
for parts_used in range(2 ** parts):
for options in range(2 ** parts):
for pos in range(parts):
pos_neg = int('{0:0{1}b}'.format(options,parts)[pos]) * 2 - 1
use = int('{0:0{1}b}'.format(parts_used,parts)[pos])
cv[pos] = p[pos] * pos_neg * use
if sum(cv) == check_weight:
if show_result:
print("{} = sum of:{}".format(check_weight, cv))
sum_ok = True
break
if sum_ok:
continue
else:
return False
return True
for part[0] in range(1,weight-parts):
for part[1] in range(part[0]+1, weight - part[0]):
for part[2] in range( part[1] + 1 , weight - sum(part[0:2])):
part[3] = weight - sum(part[0:3])
if test_solution(part,weight):
print(part)
test_solution(part,weight,True)
exit()
#!/usr/bin/env python3
weight = 121
nr_of_parts = 5
# weight = 40
# nr_of_parts = 4
weight = 13
nr_of_parts = 3
part=[0] * nr_of_parts
def test_solution(p, weight,show_result=False):
cv=[0] * nr_of_parts
for check_weight in range(1,weight+1):
sum_ok = False
for nr_of_parts_used in range(2 ** nr_of_parts):
for options in range(2 ** nr_of_parts):
for pos in range(nr_of_parts):
pos_neg = int('{0:0{1}b}'.format(options,nr_of_parts)[pos]) * 2 - 1
use = int('{0:0{1}b}'.format(nr_of_parts_used,nr_of_parts)[pos])
cv[pos] = p[pos] * pos_neg * use
if sum(cv) == check_weight:
if show_result:
print("{} = sum of:{}".format(check_weight, cv))
sum_ok = True
break
if sum_ok:
continue
else:
return False
return True
def set_parts(part,position, nr_of_parts, weight):
if position == 0:
part[position] = 1
part, valid = set_parts(part,position+1,nr_of_parts,weight)
return part, valid
if position == nr_of_parts - 1:
part[position] = weight - sum(part)
if part[position -1] >= part[position]:
return part, False
return part, True
part[position]=max(part[position-1]+1,part[position])
part, valid = set_parts(part, position + 1, nr_of_parts, weight)
if not valid:
part[position]=max(part[position-1]+1,part[position]+1)
part=part[0:position+1] + [0] * (nr_of_parts - position - 1)
part, valid = set_parts(part, position + 1, nr_of_parts, weight)
return part, valid
while True:
part, valid = set_parts(part, 0, nr_of_parts, weight)
if not valid:
print(part)
print ('No solution posible')
exit()
if test_solution(part,weight):
print(part,' ')
test_solution(part,weight,True)
exit()
else:
print(part,' ', end='\r')