我想解決一個Prolog中的一個難題,它涉及到一個數字的平方(數字列表),並返回從上到下依次排列的數字的最大組合列表。每次移動必須向下,向右或向左移動。如何在Prolog中解決這個難題?
我一直在試圖做一段時間,現在有沒有人有我可以開始的地方?
例如,在板
[[0, 2, 1, 0],
[0, 1, 1, 0],
[0,10,20,30]]
最好行動將是[1, 2, 3]
爲33分。
我想解決一個Prolog中的一個難題,它涉及到一個數字的平方(數字列表),並返回從上到下依次排列的數字的最大組合列表。每次移動必須向下,向右或向左移動。如何在Prolog中解決這個難題?
我一直在試圖做一段時間,現在有沒有人有我可以開始的地方?
例如,在板
[[0, 2, 1, 0],
[0, 1, 1, 0],
[0,10,20,30]]
最好行動將是[1, 2, 3]
爲33分。
因此,這裏是你如何能做到這一點。我知道這有點羅嗦,這可能是因爲我在Prolog中不是很流利......
% Lookup a value in a list by it's index.
% this should be built into prolog?
at(0, [H|_], H).
at(N, [_|T], X) :-
N > 0,
N1 is N - 1,
at(N1, T, X).
% like Haskell's maximumBy; takes a predicate, a
% list and an initial maximum value, finds the
% maximum value in a list
maxby(_, [], M, M).
maxby(P, [H|T], M0, M) :-
call(P, H, M0, M1),
maxby(P, T, M1, M).
% which of two paths has the bigger score?
maxval(path(C, I), path(C1, _), path(C, I)) :- C >= C1.
maxval(path(C0, _), path(C, I), path(C, I)) :- C0 < C.
% generate N empty paths as a starting value for
% our search
initpaths(N, Ps) :-
findall(path(0, []),
between(0, N, _),
Ps).
% given the known best paths to all indexes in the previous
% line and and index I in the current line, select the best
% path leading to I.
select(Ps, I, N, P) :-
I0 is I-1,
I1 is I+1,
select(Ps, I0, N, path(-1, []), P0),
select(Ps, I, N, P0, P1),
select(Ps, I1, N, P1, P).
% given the known best paths to the previous line (Ps),
% an index I and a preliminary choice P0, select the path
% leading to the index I (in the previous line) if I is within
% the range 0..N and its score is greater than the preliminary
% choice. Stay with the latter otherwise.
select(_, I, _, P0, P0) :- I < 0.
select(_, I, N, P0, P0) :- I > N.
select(Ps, I, _, P0, P) :-
at(I, Ps, P1),
maxby(maxval, [P0], P1, P).
% given the known best paths to the previous line (P1),
% and a Row, which is the current line, extend P1 to a
% new list of paths P indicating the best paths to the
% current line.
update(P1, P, Row, N) :-
findall(path(C, [X|Is]),
(between(0, N, X)
, select(P1, X, N, path(C0, Is))
, at(X, Row, C1)
, C is C0 + C1),
P).
% solve the puzzle by starting with a list of empty paths
% and updating it as long as there are still more rows in
% the square.
solve(Rows, Score, Path) :-
Rows = [R|_],
length(R, N0),
N is N0 - 1,
initpaths(N, IP),
solve(N, Rows, IP, Score, Path).
solve(_, [], P, Score, Path) :-
maxby(maxval, P, path(-1, []), path(Score, Is0)),
reverse(Is0, Path).
solve(N, [R|Rows], P0, Score, Path) :-
update(P0, P1, R, N),
solve(N, Rows, P1, Score, Path).
我們試試嗎?這裏是你的例子:
?- solve([[0,2,1,0], [0,1,1,0], [0,10,20,30]], Score, Path).
Score = 33,
Path = [1, 2, 3] ;
false.
?- solve([[0,1,1], [0,2,1], [10,0,0]], Score, Path).
Score = 13,
Path = [1, 1, 0] ;
false.
通常可用作第nth0/3 – mat 2012-04-04 13:42:53
我的序言有點不穩定。實際上我所記得的關於序言的一點是它是聲明性的。
這裏有一些haskell代碼來查找最大路徑的值。尋找蹤跡應該是一個簡單的下一步,但是我想象的代碼更復雜一點。我想一個非常優雅的跟蹤解決方案將使用單子。
maxValue :: [ [ Int ] ] -> Int
maxValue p = maximum $ maxValueHelper p
maxValueHelper :: [ [ Int ] ] -> [ Int ]
maxValueHelper [ row ] = row
maxValueHelper (row : restOfRows) = combine row (maxValueHelper restOfRows)
combine :: [ Int ] -> [ Int ]-> [ Int ]
combine [ x ] [ y ] = [ x + y ]
combine (x1 : x2 : lx) (y1 : y2 : ly) =
let (z2 : lz) = combine (x2 : lx) (y2 : ly)
in
(max (x1 + y1) (x1 + y2) : max (x2 + y1) z2 : lz)
main :: IO()
main = print $ maxValue [[0,2,1,0], [0,1,1,0], [0,10,20,30]]
感謝您的迴應:) 我已經開始了一個謂詞。 我希望它有三個參數:一個板,一個起始列和一個從開始列開始的板子的合法路徑。 – user1204349 2012-04-03 21:57:14
您也可以使用它來生成合法路徑。例如: '5? - legalPathStarting([[10,20,30,40]],2,路徑)。 Path = path(30,[2]);' false.' – user1204349 2012-04-03 22:01:35
這是功課嗎? – 2012-04-03 22:13:00
?- best_path_score([[0, 2, 1, 0],[0, 1, 1, 0],[0,10,20,30]], P, S).
P = [1, 2, 3],
S = 33.
這一定義
best_path_score(Rs, BestPath, BestScore) :-
aggregate_all(max(Score, Path), a_path(Rs, Path, Score), max(BestScore, BestPath)).
a_path([R|Rs], [P|Ps], Score) :-
nth0(P, R, S0),
a_path(Rs, P, Ps, S),
Score is S0 + S.
a_path([], _, [], 0).
a_path([R|Rs], P, [Q|Qs], T) :-
(Q is P - 1 ; Q is P ; Q is P + 1),
nth0(Q, R, S0),
a_path(Rs, Q, Qs, S),
T is S0 + S.
可以定義numbers_的_greatest組合?也許一個例子可以澄清。謝謝。 – 2012-04-03 21:06:05
如果廣場是這樣 '[0,1,1] [0,2,1] [10,0,0]' 方案應該說是最好的路徑是[1,1,0 ]爲13分。 第一行中的第一個元素,第二個元素中的第一個元素和第三個中的第0個元素中的第一個元素。 – user1204349 2012-04-03 21:12:57
如果你一直在嘗試這個「現在有一段時間」,你應該能夠顯示幾乎沒有你想要的代碼。 – 2012-04-03 21:13:07