Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Prolog 如何找到排列的索引_Prolog_Permutation - Fatal编程技术网

Prolog 如何找到排列的索引

Prolog 如何找到排列的索引,prolog,permutation,Prolog,Permutation,我的解决方案: % index(+List, -Idx) Predicate will get List with permutation and I want to know index of permutation For example: ?- index([4,1,3,2],X). X= 19. 为什么错了? 我怎样才能增加对Idx的提及呢?置换/2在回溯时生成元素。跟踪解决方案的索引并不容易,因此这是解决当前问题的更简单方法: index([],0)

我的解决方案:

% index(+List, -Idx) Predicate will get List with permutation and I want to
know index of permutation

For example: ?- index([4,1,3,2],X).
                X= 19.
为什么错了?
我怎样才能增加对Idx的提及呢?

置换/2在回溯时生成元素。跟踪解决方案的索引并不容易,因此这是解决当前问题的更简单方法:

index([],0).
index([_],1).
index([X,Y],2):- Y > X.
index([H,X|T],Idx):-index([X|T],Idx+1),H > X.
编辑

更有效的东西,可以用这个

?- findall(P,permutation([1,2,3,4],P),L), nth0(I,L,[4,1,3,2]).                                                                                                                                             L = [[1, 2, 3, 4], [1, 2, 4, 3], [1, 3, 2, 4], [1, 3, 4, 2], [1, 4, 2, 3], [1, 4, 3|...], [2, 1|...], [2|...], [...|...]|...],
I = 19 ;
false.
这样:

nthsol(Goal, N) :-
    State = state(0, _),
    Goal,
    arg(1, State, C),
    N is C+1,
    nb_setarg(1, State, N).

索引现在是一个计数器,所以它被1抵消了。我找到了相同想法的更清晰版本,所以我显示了代码:

?- nthsol(permutation([1,2,3,4],P),I),P=[4,1,3,2].
P = [4, 1, 3, 2],
I = 20 ;
false.
你可以看到指数正好是26-2所以也许这是正确的?下面您可以找到原始答案,其中有一些算法的解释和不足的实现。这个实现不是很好,但我希望它至少好一点


你真的想列举所有可能的排列吗?在很多情况下这可能太多了?例如,如果您对英语字母表中的所有字母进行了排列,那么您已经有26个了!=一个非常大的数字(40329146112605684000000)

因此,也许只计算而不枚举更好?另外,我认为库
permutation/2
没有这个选项,但是您应该能够按照字典顺序计算“next permutation”,而不必枚举所有排列。因为当你说“排列索引”时,这假设所有可能的排列都是以某种顺序排列的,但你没有说这是什么顺序。也许是字典顺序?而库
permutation/2
与@capelical的另一个答案一样,有一个恼人的“特征”,即它不在乎它是否真的是一个置换:

?- bagof(C, ( char_type(C, lower), C @> b, C @=< z ), Cs),
   reverse(Cs, Cs_rev),
   append(Cs_rev, [a,b], Letters),
   time( permutation_index(Letters, I) ).
% 1,103 inferences, 0.000 CPU in 0.000 seconds (98% CPU, 4226847 Lips)
Cs = [c, d, e, f, g, h, i, j, k|...],
Cs_rev = [z, y, x, w, v, u, t, s, r|...],
Letters = [z, y, x, w, v, u, t, s, r|...],
I = 403291461126605635583999998.
在我看来,这一点都不正确。如果你问你的程序,“排列索引[1,1,1]是什么,它是否应该回答“它是1,2,3,4,5,6?”我对这个答案感到非常不舒服

在你开始问“排列的索引是什么”之前,首先你需要问“排列是如何排序的?”(按字典顺序排列的??)您还需要确保列表中的所有元素实际上都是唯一的,并且它们也有一个顺序。我假设如果列表的长度为n,那么在这个列表中,所有整数都在1到n之间,就像您的示例一样!!!如果您有其他元素(如字母)然后,您必须确保它们是唯一的,并且可以排序,然后您可以为它们分配介于1和n之间的数字,但我认为这很简单,所以我不想为其编写代码。但它可以如下所示:

?- permutation([1,1,1], P).
P = [1, 1, 1] ;
P = [1, 1, 1] ;
P = [1, 1, 1] ;
P = [1, 1, 1] ;
P = [1, 1, 1] ;
P = [1, 1, 1] ;
false.
你知道为什么吗?如果没有,我可以解释为什么这很重要

一旦你有了一个类似于[4,1,3,2]的列表及其长度,你就可以使用以下算法:

?- list_indices_len([c,b,a,x], Ns, Is, Len).
Ns = [3, 2, 1, 4],
Is = [1, 2, 3, 4],
Len = 4.
这已经知道了排列和列表的长度,因为我们使用
list\u index\u len/4
创建了它。现在我们只需执行n-1步,每次我们将剩余数字列表中数字的0基索引与剩余数字的阶乘相乘

permutation_index(P, Es, Len, I) :-
    succ(Len0, Len),
    P = [N|Ns],
    permutation_index(Ns, N, Len0, Es, 0, I).
一定有更好的方法来计算阶乘,但这有效吗

所以现在我得到了预期的结果:

permutation_index([], _, _, _, I, I).
permutation_index([N|Ns], N0, X, Es, Acc, I) :-
    once( nth0(N_i, Es, N0, Es0) ),
    factorial_expr(X, X_fac),
    succ(X0, X),
    Acc1 is N_i*X_fac + Acc,
    permutation_index(Ns, N, X0, Es0, Acc1, I).

factorial_expr(F, E) :-
    (   F =:= 0
    ->  E = 1
    ;   F =:= 1
    ->  E = 1
    ;   F > 1
    ->  X is F,
        numlist(2, X, [N|Ns]),
        foldl(prod, Ns, N, E)
    ).

prod(X, Y, Y*X).
最后一个正好是10!-2

如果你需要更多的解释,我可以做,但是如果你能理解逻辑的话,看起来很容易理解。或者我对逻辑的理解是错误的?但是它似乎是有效的

我自己做了测试,以确保我不会对我的方法的复杂性感到困惑,所以我用更大的数字再次测试,结果看起来是正确的

?- permutation_index([4,1,3,2], [1,2,3,4], 4, I).
I = 19.

?- permutation_index([4,3,2,1], [1,2,3,4], 4, I).
I = 23.

?- permutation_index([1,2,3,4], [1,2,3,4], 4, I).
I = 0.

?- permutation_index([1,2,4,3], [1,2,3,4], 4, I).
I = 1.

?- permutation_index([10,9,8,7,6,5,4,3,1,2], [1,2,3,4,5,6,7,8,9,10], 10, I).
I = 3628798.
还有更有效的方法来计算排列索引,但也许您应该先阅读……您可以从一开始就开始:


我认为这是一个很好的答案,我给你投票,但你不认为如果你给它一个更大的列表,它会持续一段时间吗?我不确定如果你给它一个没有唯一元素的列表,会发生什么,那么[1,1,1],它会给你一些奇怪的结果。我试着用另一个答案来回答您对原始问题的回答中的问题。nthsol/2它尽可能有效-但一般来说,您要解决的问题可能很微妙,也很难解决,因为Prolog执行可能是一个复杂的过程。第一个选择(使用findall/3)当然,存储所有的排列只是为了找到一个索引是过分的。你可能是对的,但也许你可以只计算“索引”“直接从数字开始?我用芬兰语写了答案,我展示了如何,如果你认为我错了,你可以说,这很自然。对不起,我不明白你的意思。。。你有别的答案吗?当然,我们都很感兴趣……为什么不使用
call\n/2
?一个高度技术性的答案。。。代码不是很容易理解。对阶乘使用nth0/4或foldl/4(它有一个单行定义为
fact(X,F):-(X>0->Y是X-1,fact(Y,G),F是X*G;F=1)。
)将给OP带来困难(我假设它是Prolog的初学者)。此外,消化莱默的代码以及与索引的关系并不容易。这不是莱默的代码。这不太新奇,但适用于任何大小。我并不是说这比你的答案更好,为什么你说“高度技术化”,而这是一个非常基本的算术,我想:-(这只是一个乘积的总和。我使用nth0/4和foldl只是为了省去键入,当然你对阶乘的定义更好,但我不能想出它,因为我不太擅长Prolog。@我明白,创建所有排列并使用一些全局变量(如普通循环)对它们进行计数更容易我很乐意尝试一下,看看是否有更复杂的方法更不容易获得。谢谢你的反馈。听到其他程序员的想法总是很好的,因为学习编写好的代码并不容易,而且当我们知道更好的程序员如何编写和阅读代码以使其更好时,这会更容易。你的代码非常好,而且很有趣回答!背后的数学是可怕的——至少对我来说是这样。
?- permutation_index([4,1,3,2], [1,2,3,4], 4, I).
I = 19.

?- permutation_index([4,3,2,1], [1,2,3,4], 4, I).
I = 23.

?- permutation_index([1,2,3,4], [1,2,3,4], 4, I).
I = 0.

?- permutation_index([1,2,4,3], [1,2,3,4], 4, I).
I = 1.

?- permutation_index([10,9,8,7,6,5,4,3,1,2], [1,2,3,4,5,6,7,8,9,10], 10, I).
I = 3628798.
?- time(permutation_index([12,11,10,9,8,7,6,5,4,3,1,2], [1,2,3,4,5,6,7,8,9,10,11,12], 12, I)).
% 466 inferences, 0.000 CPU in 0.000 seconds (99% CPU, 1498045 Lips)
I = 479001598.

?- factorial_expr(12, E), X is E - 2.
E = ... * ... * 4*5*6*7*8*9*10*11*12,
X = 479001598.