我有一个(可能很大的)列表数据
,包含三个小的非负整数元组,比如
data = [
(1, 0, 5),
(2, 4, 2),
(3, 2, 1),
(4, 3, 4),
(3, 3, 1),
(1, 2, 2),
(4, 0, 3),
(0, 3, 5),
(1, 5, 1),
(1, 5, 2),
]
我想对data
中的元组进行排序,以便相邻的元组(data[I]
和data[i1]
)“尽可能相似”。
定义两个三元组的不相似性为它们之间不相等的元素的数量。例如。
(0,1,2)
vs.(0,1,2)
:差异0
.(0,1,2)
vs.(0,1,3)
:差异1
.(0,1,2)
vs.(0,2,1)
:差异2
.(0,1,2)
vs.(3,4,5)
:差异3
.(0,1,2)
vs.(2,0,1)
:差异3
.问题:寻找数据
排序的好算法是什么,它可以最小化所有相邻三元组之间的差异之和?
下面是一个计算两个三元组之间差异的函数:
def dissimilar(t1, t2):
return sum(int(a != b) for a, b in zip(t1, t2))
这里有一个函数,它计算data
的相加总差异,即我寻求最小化的数字:
def score(data):
return sum(dissimilar(t1, t2) for t1, t2 in zip(data, data[1:]))
只需在数据的每个排列上运行score()
,就可以解决这个问题:
import itertools
n_min = 3*len(data) # some large number
for perm in itertools.permutations(data):
n = score(perm)
if n < n_min:
n_min = n
data_sorted = list(perm)
print(data_sorted, n_min)
虽然上面的方法有效,但它非常慢,因为我们显式地检查每个置换(导致O(N!))复杂性)。在我的机器上,当数据
有10个元素时,上述过程大约需要20秒。
为了完整起见,以下是在给定示例data
的情况下运行上述操作的结果:
data_sorted = [
(1, 0, 5),
(4, 0, 3),
(4, 3, 4),
(0, 3, 5),
(3, 3, 1),
(3, 2, 1),
(1, 5, 1),
(1, 5, 2),
(1, 2, 2),
(2, 4, 2),
]
使用n_min=15
。请注意,还有几个分数为15
的订单(10
)。就我而言,这些都是等价的,我只想要其中一个。
在实践中,data
的大小可能与10000
一样大。
广受追捧的算法应该比O(N!),i、 e.在时间(和空间)上可能是多项式。
如果不存在这样的算法,我会对“近似解”感兴趣,即一种快速算法,它给出数据
的排序,总分数很小,但不一定最小。其中一种算法是字典排序,即。
sorted(data) # score 18
虽然我希望能做得更好。
这不是精确的算法,只是启发式的,但应该比简单的排序更好:
# you can sort first the data for lower total average score:
# data = sorted(data)
out = [data.pop(0)]
while data:
idx, t = min(enumerate(data), key=lambda k: dissimilar(out[-1], k[1]))
out.append(data.pop(idx))
print(score(out))
测试(100次重复,数据len(data)=1000
):
import random
from functools import lru_cache
def get_data(n=1000):
f = lambda n: random.randint(0, n)
return [(f(n // 30), f(n // 20), f(n // 10)) for _ in range(n)]
@lru_cache(maxsize=None)
def dissimilar(t1, t2):
a, b, c = t1
x, y, z = t2
return (a != x) + (b != y) + (c != z)
def score(data):
return sum(dissimilar(t1, t2) for t1, t2 in zip(data, data[1:]))
def lexsort(data):
return sorted(data)
def heuristic(data, sort_data=False):
data = sorted(data) if sort_data else data[:]
out = [data.pop(0)]
while data:
idx, t = min(enumerate(data), key=lambda k: dissimilar(out[-1], k[1]))
out.append(data.pop(idx))
return out
N, total, total_lexsort, total_heuristic, total_heuristic2 = 100, 0, 0, 0, 0
for i in range(N):
data = get_data()
r0 = score(data)
r1 = score(lexsort(data))
r2 = score(heuristic(data))
r3 = score(heuristic(data, True))
print("original data", r0)
print("lexsort", r1)
print("heuristic", r2)
print("heuristic with sorted", r3)
total += r0
total_lexsort += r1
total_heuristic += r2
total_heuristic2 += r3
print("total original data score", total)
print("total score lexsort", total_lexsort)
print("total score heuristic", total_heuristic)
print("total score heuristic(with sorted)", total_heuristic2)
打印:
...
total original data score 293682
total score lexsort 178240
total score heuristic 162722
total score heuristic(with sorted) 160384
这里有一个小的改进,不确定其复杂性,似乎是关于O(4n)。在不到一秒钟的时间内求解N=10。它对于大型案例来说太慢了,但对于测试其他解决方案可能很有用,因为它可以更快地计算测试输入的预期结果。
这个想法是,在N个三元组中,其中一个必须是中心。所以试着以每一个为中心。让half=N//2
。然后,其他三元组的half
必须位于中心的左侧,而N-1-half
必须位于中心的右侧。尝试将所有拆分为左侧和右侧,并独立递归地解决它们。
我的助手函数不仅接受了data
中的三元组,还接受了它所属的上下文:数据必须包含在head
三元组和ail
三元组之间(两者都可以是无
),并且分数必须相应地计算。
import itertools
data = [
(1, 0, 5),
(2, 4, 2),
(3, 2, 1),
(4, 3, 4),
(3, 3, 1),
(1, 2, 2),
(4, 0, 3),
(0, 3, 5),
(1, 5, 1),
(1, 5, 2),
]
def dissimilar(t1, t2):
if t1 and t2:
a, b, c = t1
x, y, z = t2
return (a != x) + (b != y) + (c != z)
return 0
def score(data):
return sum(dissimilar(t1, t2) for t1, t2 in zip(data, data[1:]))
def solve(data):
def solve(head, data, tail):
if len(data) <= 3:
perm = min(itertools.permutations(data),
key=lambda perm: score([head, *perm, tail]))
return list(perm), score([head, *perm, tail])
half = len(data) // 2
result = result_score = None
for center in list(data):
data.remove(center)
for left in itertools.combinations(data, half):
left = set(left)
right = data - left
left, score_left = solve(head, left, center)
right, score_right = solve(center, right, tail)
if result_score is None or score_left + score_right < result_score:
result = [*left, center, *right]
result_score = score_left + score_right
data.add(center)
return result, result_score
return solve(None, set(data), None)
result, result_score = solve(data)
print(result, result_score, score(result), sorted(result) == sorted(data))
不幸的是,这个问题是NP完全问题。你可以通过平面3-正则二部图上的哈密顿路径问题的简化来证明这一点,这也是NP完全的。
作为证明的概述:我们将为图的每个顶点创建一个3元组,这样,如果顶点相邻,对应的3元组对的相异性等于2,如果顶点不相邻,相异性等于3。每个顶点的3元组的成员将唯一地对应于顶点的关联边。
证明:
假设我们的输入是一个无向平面三次二部图G=(V,E)
,我们试图在其上找到哈密顿路径。我们可以在线性时间内找到边的3-着色。假设我们的三种边缘颜色是0、1、2
。对于e
中的每个边e
,给它一个唯一的自然数标签L(e)
,这样L(e)mod 3
就等于e
的颜色。
我们可以用颜色0、1和2给边缘上色:
然后用最小自然数L(e)标记边缘,该自然数与mod 3的颜色有关:
对于V
中的每个顶点v
,创建一个3-TupleT=(t0, t1, t2)
,其中t0, t1, t2
是入射到v
的边的标签,余数分别等于0,1,2
。请注意,每个边的标签出现在它所属的每个3-Tuple的相同索引处。在上述示例中,左上角的顶点将得到一个3-Tuple(0,1,29)
,最左边的顶点将得到一个3-Tuple(0,16,32)
。
现在,在G
中存在哈密顿路径,当且仅当存在具有不相似性和2*(|V|-1)
的3-元组排序时。这是因为3-元组排序具有不相似性和,当且仅当排序对应于G
中的哈密顿路径。
参考文献和附录
证明中使用的简化来自于哈密顿路径问题的一个非常具体的版本。证明中使用的这类图(即平面、立方、二部图)的唯一性质是:
问题内容: 我有计算纯python中相邻元素之间差异的算法: 有什么办法可以用Numpy重写此功能? 问题答案: 有方法: 退货
我有一堆4个光栅。我想要一个像素和它的8个相邻像素之间的平均时间相关性。 一些数据: 因此,对于位置x处的像素,在NE、E、SE、S等位置有8个相邻像素,我想要 以及保存在结果光栅中位置x处的平均值。边缘单元格将是NA,或者,如果可能的话,使用一个标志来计算与它所接触的单元格(3或5个单元格)的平均相关性。谢谢
SameGame示例 让我们以一个SameGame板为例。 如果两个块有一个共同的边,则它们是相邻的。组是由至少两个块组成的集合,所有块都是相同类型的,并且每个块都与组的至少一个其他成员相邻。当鼠标悬停在作为组的一部分的块上时,整个组应在视觉上突出显示。 举个矩阵的例子: 鼠标悬停怎么找一套? 我想过递归,但老实说,我不知道该怎么做。BFS似乎是我可以做的事情,但对于这样一个“简单”的事情来说,它
我正在寻找一个函数,使列表尽可能未排序。最好是Python。 背景故事: 我想检查URL的状态,看看URL是否给出404。我只是使用和模块。没什么花哨的。 现在我不想让服务器过载,所以我想尽量减少同时检查同一域名上的网址。我有这样的想法来排序的URL的方式是项目是彼此接近(具有相同的排序键=域名)被放置尽可能远的彼此在列表中。 以数字为例: 可以不分类为: 我想说的是,我们可以通过将相等项(具有相
有没有一种方法可以在小于O(n^2)的时间内做到这一点。 O(nlogn)还是O(n)?
本文向大家介绍在JavaScript中查找大于其相邻元素的元素,包括了在JavaScript中查找大于其相邻元素的元素的使用技巧和注意事项,需要的朋友参考一下 我们需要编写一个JavaScript函数,该函数将数字数组作为第一个也是唯一的参数。 函数应从数组中查找并返回一个大于两者的数字,该数字应位于其直接右侧和左侧。如果数组中存在多个这样的元素,则我们的函数应返回其中任何一个。 例如- 如果输入