Created
March 8, 2011 09:37
-
-
Save ericliang/860090 to your computer and use it in GitHub Desktop.
Illustrate the dynamic programming in subset_sum_problem
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env escript | |
%% -*- erlang -*- | |
%%! -smp enable -sname subset_sum_problem | |
%% | |
%% Illustrate the dynamic programming in subset_sum_problem: | |
%% http://en.wikipedia.org/wiki/Subset_sum_problem#Pseudo-polynomial_time_dynamic_programming_solution | |
%% | |
main(_) -> | |
L = [1,-3,2,4], | |
% L = [1 | lists:append( lists:duplicate(20, -20) , lists:duplicate( 19,1) )], %%2s | |
% L = lists:append( lists:duplicate(40, -200) , lists:duplicate( 20,10) ), %% | |
SS = subset_with_sum_equal_zero(L), | |
[ io:format("Subsets: ~p~n",[S]) || S<-SS ]. | |
subset_with_sum_equal_zero(L) -> | |
subset_with_sum_equal_x(L, 0). | |
subset_with_sum_equal_x([I],X) -> | |
case I==X of | |
true -> | |
[[I]]; | |
false -> | |
[] | |
end; | |
subset_with_sum_equal_x(L,X) -> | |
io:format("DEBUG: L: ~p ~n",[L]), | |
L1 = lists:sort(L), | |
{Negs,Poss} = lists:splitwith(fun(I) -> I < 0 end, L1), | |
% io:format("DEBUG: NEG:~p POS:~p~n",[Negs,Poss]), | |
SumNeg=lists:sum(Negs), | |
SumPos=lists:sum(Poss), | |
if X > SumPos orelse X < SumNeg -> | |
[]; | |
true -> | |
M = make_matrix(L, SumNeg, SumPos), | |
io:format("DEBUG: MATRIX: ~p~n",[M]), | |
case find_subset_sum_equal_x(L, M, SumNeg, X) of | |
[] -> | |
[]; | |
S -> | |
[S] | |
end | |
end. | |
make_matrix([H|T], LB, UB) -> | |
Row = first_row(H, LB, UB), | |
make_matrix( T, LB, UB, [Row]). | |
make_matrix([], _, _, M) -> | |
lists:reverse(M); | |
make_matrix([H|T], LB, UB, [Prev|_] = M) -> | |
Row = make_row(H, Prev, LB, UB), | |
make_matrix(T, LB, UB, [Row|M]). | |
first_row(H, LB, UB) -> | |
Row = lists:append(lists:duplicate(H-LB,0), [1|lists:duplicate(UB-H,0)]), | |
list_to_tuple( Row ). | |
make_row(H, Prev, LB, UB) -> | |
make_row(H, Prev, LB, UB, 0, UB-LB+1,[]). | |
make_row(_, _, _, _, _, 0, Row ) -> | |
list_to_tuple( lists:reverse(Row) ); | |
make_row(H, Prev, LB, UB, Iter1, Iter2, Row ) -> | |
S = LB+Iter1, | |
case S-H of | |
0 -> | |
make_row(H, Prev, LB, UB, Iter1+1, Iter2-1, [1|Row]); | |
D -> | |
case element(Iter1+1, Prev) of | |
1 -> | |
make_row(H, Prev, LB, UB, Iter1+1, Iter2-1, [1|Row]); | |
_ -> | |
case D >= LB andalso D =< UB | |
andalso element( D-LB+1, Prev) of | |
1 -> | |
make_row(H, Prev, LB, UB, Iter1+1, Iter2-1, [1|Row]); | |
_ -> | |
make_row(H, Prev, LB, UB, Iter1+1, Iter2-1, [0|Row]) | |
end | |
end | |
end. | |
find_subset_sum_equal_x(L, M, SumNeg, X) -> | |
find_subset_sum_equal_x(lists:reverse(L), lists:reverse(M), SumNeg, X, []). | |
find_subset_sum_equal_x([H], [NowRow], SumNeg, X, S) -> | |
Num = X-SumNeg+1, | |
case element(Num, NowRow) of | |
1 -> | |
[H|S]; | |
_ -> | |
[] | |
end; | |
find_subset_sum_equal_x([H|T], [NowRow,PrevRow|M], SumNeg, X, S) -> | |
Num = X-SumNeg+1, | |
case {element(Num, NowRow), element(Num, PrevRow)} of | |
{1,0} -> | |
find_subset_sum_equal_x(T, [PrevRow|M], SumNeg, X-H, [H|S]); | |
{1,1} -> | |
find_subset_sum_equal_x(T, [PrevRow|M], SumNeg, X, S); | |
{0,_} -> | |
[] | |
end. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment