旅行推销员


17

给您一个列表或向量或其他任何东西,一堆3元组或其他任何东西,其中前两个是字符串,第三个是一个数字。字符串是城市,数字是它们之间的距离。元组中城市的顺序是任意的(即,先到先后都没关系),因为每种方式的距离相同。另外,每对连接的城市都有一个元组。并非所有城市都可以连接。而且,距离始终为正(不是0)。您不需要检查这些条件,可以假设输入格式正确。您的工作是按循环顺序返回城市,这样,如果您从任何一个城市开始,然后按顺序返回同一城市,则城市之间的总距离将最小(确切地说,总之情况。)您可以假设存在解决方案。例如,假设您被授予

[("New York", "Detroit", 2.2), ("New York", "Dillsburg", 3.7), ("Hong Kong", "Dillsburg", 4), ("Hong Kong", "Detroit", 4), ("Dillsburg", "Detroit", 9000.1), ("New York", "Hong Kong", 9000.01)]

您可以输出以下任何内容(但只需要输出一个):

["Detroit","Hong Kong","Dillsburg","New York"]
["Hong Kong","Dillsburg","New York","Detroit"]
["Dillsburg","New York","Detroit","Hong Kong"]
["New York","Detroit","Hong Kong","Dillsburg"]
["Dillsburg","Hong Kong","Detroit","New York"]
["New York","Dillsburg","Hong Kong","Detroit"]
["Detroit","New York","Dillsburg","Hong Kong"]
["Hong Kong","Detroit","New York","Dillsburg"]

因为那是最短的行程:13.9

但不是

["Dillburg","Detroit","New York","Hong Kong"]

因为它不是最短的。

参见en.wikipedia.org/wiki/Travelling_salesman_problem

计分

这就是它变得有趣的地方。您可以使用拥有的字符数,然后将它们插入最坏的O表示公式中。例如,假设您编写了一个42个字符的蛮力程序。众所周知,最坏的情况是城市数n!在哪里n。42!= 1405006117752879898543142606244511569936384000000000,所以这是您的分数。该得分最低胜

注意:此后我也松了一口气,但不确定如何解决它,希望没人注意。人们做到了,所以我将接受issacg的建议:

唯一的选择是O(n!)和O(b ^ n n ^ a ln(n)^ k),并且在给定表示法的情况下,所有边界都必须尽可能紧密


4
但是,您怎么说别人的代码O(n!)不是,O(sqrt(n)*n^n/e^n)也不是O(n!/100000000000000000000)
jimmy23013

1
@ user23013一种解决方案是说,唯一的选择是O(n!)O(b^n*n^a*ln(n)^k),并且给定该表示法,所有边界必须尽可能紧密。不过,OP应该澄清。
isaacg 2014年

2
@Geobits如漫画中所示,动态编程解决方案是O(n^2*2^n),比O(n!)大n的要小得多。
isaacg 2014年

@proud haskeller好的(实际上已经有一段时间了,我只是想接受它,因为尽管几乎没有选票,但这是最好的,但是如果您有更好的选择,那就继续吧。)
PyRulez

@PyRulez很好,无论我尝试什么,我都说服自己具有O(n!)的复杂性……它很复杂
骄傲的haskeller

Answers:


5

哈斯克尔(259)

我以为我可以把它缩短。也许我会。
时间复杂度为O(n ^ 2 * 2 ^ n)*,所以分数约为6.2e82

*我实际上不确定,但是如果对复杂度有任何“加法”,则仅是多项式,因此这不会对分数产生太大影响。

import Data.List
g e=tail$snd$minimum[r|r@(_,b)<-iterate(\l->nubBy((.f).(==).f)$sort[(b+d,c:a)|(b,a)<-l,c<-h\\init a,d<-a!!0%c])[(0,[h!!0])]!!length h,b!!0==h!!0]where h=sort$nub$e>>= \(a,b,_)->[a,b];a%b=[z|(x,y,z)<-e,x==a&&y==b||x==b&&y==a]
f(_,x:b)=x:sort b

已经有一段时间了,但是有没有可用的“非最小化”版本(可能带有注释)?我很好奇您如何使用Haskell解决此问题。
Henk Mollema

5

Python 2,237 231 228 225个字符

由于这是一个幼稚的算法,其分数可能约为225!≈1.26e433。

from itertools import*
a=input()
n=lambda*a:tuple(sorted(a))
d=dict((n(*x[:2]),x[2])for x in a)
print min(permutations(set(chain(*[x[:2]for x in a]))),key=lambda x:sum(d.get(n(x[i],x[i+1]),1e400)for i in range(-1,len(x)-1)))

from itertools import*会更短。
seequ 2014年

哦,好主意..!
Greg Hewgill 2014年

我现在无法测试,所以我只是提出想法。设置必要吗?
seequ 2014年

该集合用于消除城市列表中的重复项。由于输入不包含像之类的条目("a", "a", 0),因此在某处需要额外的逻辑以跳过零长度的边。(如果您在网络上,可以随时使用codepad.org等进行测试。
Greg Hewgill 2014年

我对Python不太了解,但是显然您已经调用sum了每个排列项。那不是O(n!*n)吗?
jimmy23013

4

朱莉娅213个字符

大概是这样n!n,所以〜2e407。

a=[("New York", "Detroit", 2.2), ("New York", "Dillsburg", 3.7), ("Hong Kong", "Dillsburg", 4), ("Hong Kong", "Detroit", 4), ("Dillsburg", "Detroit", 9000.1), ("New York", "Hong Kong", 9000.01)]
f(a)=(
d(x,y)=(r=filter(z->x in z&&y in z,a);r==[]?Inf:r[1][3]);
m=Inf;
q=0;
c=unique([[z[1] for z=a],[z[2] for z=a]]);
n=length(c);
for p=permutations(c);
    x=sum([d(p[i],p[mod1(i+1,n)]) for i=1:n]);
    x<m&&(m=x;q=p);
end;
q)
f(a)

为了便于阅读和演示使用,我留了一些未评分的换行符和制表符,以及示例输入和对该函数的调用。我还使用了一种算法,该算法需要n!时间,但不需要n!内存,因此运行起来稍微可行一些。


调用sum每个排列项。那不是O(n!* n)吗?
jimmy23013

是的,我认为您是对的。
gggg 2014年

2

Python 3-491

我没有计算输入图变量的长度g。该解决方案使用动态编程,复杂度为n ^ 2 * 2 ^ n,总得分约为6.39e147。我还是打高尔夫球的新手,所以如果您在某处看到大量的代码浪费,请进来!

g=[("New York", "Detroit", 2.2), ("New York", "Dillsburg", 3.7), ("Hong Kong", "Dillsburg", 4), ("Hong Kong", "Detroit", 4), ("Dillsburg", "Detroit", 9000.1), ("New York", "Hong Kong", 9000.01)]
s=''
c={s:1}
D={}
for t in g:c[t[0]]=1;c[t[1]]=1;D[(t[0],t[1])]=t[2];D[(t[1],t[0])]=t[2];D[('',t[0])]=0;D['',t[1]]=0
V={}
y=[x for x in c.keys() if x!='']
f=''
def n(z,p):
 if(len(p)==len(y)-1):
  global f;f=z
 if(0==len(p)):
  return (D[(z,f)] if (z,f) in D else float('inf'))
 Y=[(float('inf'),'')]
 for P in p:
  if((z,P) in D):
   Y.append((D[(z,P)] + n(P,[m for m in p if m!=P]), P))
 V[(z,tuple(p))]=min(Y)
 return min(Y)[0]
n('',y)
for i in range(len(c)-1):
 N=V[(s,tuple(y))][1]
 print(N)
 s=N
 y.remove(N)

1

Mathematica,66个字节

Most@Last@FindShortestTour@Graph[#<->#2&@@@#,EdgeWeight->Last/@#]&

不知道复杂性,所以分数在10^23和之间10^93


0

红宝石, 198 180字节

G=eval(gets.tr("()","[]"))
C=G.map{|t|[t[0],t[1]]}.flatten.uniq
D=Hash.new(+1.0/0)
G.map{|p|D[[p[0],p[1]]]=D[[p[1],p[0]]]=p[2]}
p C.permutation.map{|l|d=0;p=l[-1];l.map{|c|d+=D[[p,c]];p=c};[d,l]}.sort[0][1]

读取输入内容的第一行没有评分,因为这似乎是其他所有人正在做的事情。同样,红宝石也不需要最终的换行符。

它只是愚蠢地产生了所有城市的排列,所以让我失望了O(n!*n)。实际上,经过深思熟虑,它甚至比这还要慢,因为它对所有O(n!)路径进行了排序,而不是跟踪到目前为止的最佳状态。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.