Declaratieve Talen/Oplossing Minimale Snede: verschil tussen versies
Naar navigatie springen
Naar zoeken springen
oplossing minimale snede |
Nog eentje |
||
(6 tussenliggende versies door 3 gebruikers niet weergegeven) | |||
Regel 77: | Regel 77: | ||
del(X,[Y|Ys],[Y|Zs]) :- | del(X,[Y|Ys],[Y|Zs]) :- | ||
del(X,Ys,Zs). | del(X,Ys,Zs). | ||
== Een alternatief == | |||
<pre> | |||
boog(a,b,1). | |||
boog(a,c,1). | |||
boog(b,c,1). | |||
boog(c,z,3). | |||
boog(b,z,1). | |||
mincut(X,Y) :- | |||
findall((Opl,L),oplossingen([a],Opl,L),Rij), | |||
sort(Rij,Sorted), | |||
last(Sorted,Last), | |||
neem_minimum(Sorted,Last,(L,Y)), | |||
alle_knopen(All), | |||
vind_rechterdeel(All,L,[],R), | |||
X = (L,R). | |||
neem_minimum([],Res,Res). | |||
neem_minimum([(Links,Som)|Xs],(LL,SS),(Lres,Sres)) :- | |||
( Som < SS -> | |||
neem_minimum(Xs,(Links,Som),(Lres,Sres)) | |||
; | |||
neem_minimum(Xs,(LL,SS),(Lres,Sres))). | |||
is_bereikbaar(X,Rij,Return) :- | |||
findall(B,(boog(X,B),\+ member(B,Rij)),R), | |||
delete(R,z,Return). | |||
alle_knopen(Result) :- | |||
findall(X,boog(X,_,_),Rij1), | |||
findall(Y,boog(_,Y,_),Rij2), | |||
append(Rij1,Rij2,Rij), | |||
sort(Rij,Result). | |||
% Alle knopen, Linkerdeel, res en res | |||
vind_rechterdeel([],_,Res,Res). | |||
vind_rechterdeel([X|Rest],Rij,Res,Result) :- | |||
( member(X,Rij) -> | |||
vind_rechterdeel(Rest,Rij,Res,Result) | |||
; | |||
vind_rechterdeel(Rest,Rij,[X|Res],Result)). | |||
som_rij([],Res,Res). | |||
som_rij([X|Xs],SubRes,Res) :- | |||
NSubRes is SubRes + X, | |||
som_rij(Xs,NSubRes,Res). | |||
% Linkerdeel, rechterdeel, result | |||
bereken_som(Links,Rechts,Som) :- | |||
findall(L,(boog(X,Y,L),member(X,Links),member(Y,Rechts)),Rij), | |||
som_rij(Rij,0,Som). | |||
% Je zit in, linkerdeel, result | |||
oplossingen(Res,Res,Som) :- | |||
alle_knopen(Knopen), | |||
vind_rechterdeel(Knopen,Res,[],Rechts), | |||
bereken_som(Res,Rechts,Som). | |||
oplossingen(Rij,Result,L) :- | |||
member(M,Rij), | |||
boog(M,B,_), | |||
B \== z, | |||
\+ member(B,Rij), | |||
append(Rij,[B],Verder), | |||
oplossingen(Verder,Result,L). | |||
</pre> | |||
--[[Gebruiker:Beau|Beau]] 15 jun 2006 11:51 (CEST) | --[[Gebruiker:Beau|Beau]] 15 jun 2006 11:51 (CEST) | ||
== Een ander alternatief == | |||
Elfangor | |||
buur(X,Y,N) :- | |||
(boog(X,Y,N) ; boog(Y,X,N)). | |||
find(X,Y,snede([X|Z],[Y|W])) :- | |||
findall(A,buur(A,_,_),L), | |||
list_to_set(L,La), | |||
permutation(La,R), | |||
append([[X,Y],Z,W],R). | |||
mincut(X,Y) :- | |||
findall(C-B,(find(a,b,B), capaciteit(B,C)),L), | |||
keysort(L,[Xs-_|R]), | |||
partition(gelijk(Xs),R,Gelijken,_), | |||
pairs_values(Gelijken,Values), | |||
findall(C-B,(member(B,Values), gesneden_bogen(B,C)),A), | |||
keysort(A,[X-Y|_]). | |||
gelijk(Xs,Xs-_). | |||
capaciteit(snede(Xs,Ys), C) :- | |||
findall(N, (member(X,Xs), member(Y,Ys), buur(X,Y,N)),L), | |||
sumlist(L,C). | |||
gesneden_bogen(snede(Xs,Ys), C) :- | |||
findall(N, (member(X,Xs), member(Y,Ys), buur(X,Y,N)),L), | |||
length(L,C). | |||
== Een alternatief dat gebruik maakt van een bekend universeel zoekalgoritme == | |||
--[[Gebruiker:Nick.dewaele|Nick.dewaele]] ([[Overleg gebruiker:Nick.dewaele|overleg]]) 16 jan 2018 19:49 (CET) | |||
boog(a,b,1). | |||
boog(a,c,1). | |||
boog(b,d,1). | |||
boog(c,d,1). | |||
boog(d,z,2). | |||
neighbor(X, Y) :- boog(X,Y,_); boog(Y, X, _). | |||
vertices(V) :- findall(X, neighbor(X, _), Xs), sort(Xs, V). | |||
edges(E) :- findall(e(X,Y,W), boog(X,Y,W), E). | |||
weight(e(_,_,W), W). | |||
% Dit predicaat vindt alle bogen tussen knopen uit V en knopen uit W | |||
edgesbetween(V, W, Res) :- | |||
findall(e(X,Y,Weight), ( | |||
(member(X, V), | |||
member(Y, W) | |||
; | |||
member(Y,V), | |||
member(X, W) | |||
), | |||
boog(X,Y,Weight) | |||
), Res). | |||
sumWeightEdges(V, W, Sum) :- | |||
edgesbetween(V, W, E), | |||
maplist(weight, E, Weights), % dit is de "map" van Haskell | |||
sum_list(Weights, Sum). | |||
mincut(X,Y) :- | |||
vertices(Vert), | |||
findall(V, (member(V, Vert), \+member(V,[a,z])), InternalNodes), | |||
sumWeightEdges([a], [z], InitCost), | |||
dijkstra([InitCost-state([a], [z], InternalNodes)], X-Y). | |||
dijkstra([Cost-state(Left,Right,[V|Unassigned]) | Q], Res) :- | |||
% voeg eerst toe aan de linkerkant | |||
sumWeightEdges([V], Right, SL), | |||
CostL is Cost + SL, | |||
LeftChild = CostL-state([V|Left], Right, Unassigned), | |||
% en dan rechts | |||
sumWeightEdges([V], Left, SR), | |||
CostR is Cost + SR, | |||
RightChild = CostR-state(Left, [V|Right], Unassigned), | |||
insertPQ([LeftChild, RightChild], Q, NewQ), | |||
dijkstra(NewQ, Res). | |||
dijkstra([Cost-state(Left, Right, [])|Q], Cost-cut(L,R)) :- | |||
% De eerste op de wachtrij is nu optimaal. Als er andere doelen zijn met dezelfde kost, | |||
% dan staan die nu ook op de wachtrij. Dit is altijd het geval tenzij er bogen zijn met | |||
% gewicht 0. Ik veronderstel dat dit zich nooit voordoet. | |||
filterbest([Cost-state(Left, Right, [])|Q], OptStates), | |||
include(isGoal, OptStates, OptGoals), % dit is de "filter" van Haskell | |||
% geef 1 van de mogelijke resultaten terug. | |||
member(_-state(L,R,_), OptGoals). | |||
insertPQ(Elems, Q, NewQ) :- | |||
append(Elems, Q, Q_), | |||
sort(1, @=<, Q_, NewQ). | |||
isGoal(_-state(_,_,[])). | |||
% haal de knopen uit de (gesorteerde) wachtrij die evenveel kosten als de eerste | |||
filterbest([K-V | T], Res) :- filterbest([K-V|T], K, Res). | |||
filterbest([K-V | T], K, [K-V|Res]) :- filterbest(T, K, Res). | |||
filterbest([K-_ | _], X, []) :- K \= X. | |||
filterbest([], _, []). | |||
kleinste_mincut(X, Y) :- | |||
findall(NumEdges-Cost-cut(Left,Right), ( | |||
mincut(Cost, cut(Left,Right)), | |||
edgesbetween(Left, Right, E), | |||
length(E, NumEdges) | |||
), MinCuts), | |||
sort(1, @=<, MinCuts, Sorted), | |||
filterbest(Sorted, Best), | |||
% kies 1 oplossing | |||
member(_-X-Y, Best). |
Huidige versie van 16 jan 2018 18:49
Oplossing niet volledig maar het moeilijkste stuk is er:
boog(a,b,1). boog(a,c,1). boog(b,c,1). boog(c,z,3). boog(b,z,1). min_cut(Snede,Kost) :- findall((Snede,Kost),min_snede(Snede,Kost),R), min(R,Snede,Kost). min([(Snede,Kost)],KortsteSnede,LaagsteKost) :- KortsteSnede = Snede, LaagsteKost = Kost. min([(Snede,Kost)|Rest],KortsteSnede,LaagsteKost) :- KortsteSnede = Snede, LaagsteKost = Kost. min_rnd_snede(Snede, Kost) :- knopen(Knopen), permu(Knopen, [K|PKnopen]), min_snede_perm([K],PKnopen,Snede,Kost). %gegeven een zeker permutatie/volgorde van de knopen: ga alle snedes af min_snede_perm(X,[Y],KortsteSnede,Lengte) :- kost(snede(X,[Y]),Lengte), KortsteSnede = snede(X,[Y]). min_snede_perm([X1|X1rest],[X2|X2rest], KortsteSnede, LengteKortsteSnede) :- min_snede_perm([X2,X1|X1rest],X2rest,KortsteSubSnede,LengteKortsteSubSnede), kost(snede([X1|X1rest],[X2|X2rest]),Kost), (Kost < LengteKortsteSubSnede -> LengteKortsteSnede = Kost, KortsteSnede = snede([X1|X1rest],[X2|X2rest]); KortsteSnede = KortsteSubSnede, LengteKortsteSnede = LengteKortsteSubSnede ). %bereken de kost van een snede kost(snede([],_),Y) :- Y = 0. kost(snede([X|Xs],Y),Result) :- findall(Kost, ((boog(X,Z,Kost);boog(Z,X,Kost)),elementvan(Z,Y)),Kosten), sum(Kosten,TotaleKostX), kost(snede(Xs,Y),RecurResult), Result is RecurResult + TotaleKostX. %element van elementvan(X,[L|Lijst]) :- X == L; elementvan(X,Lijst). %bereken de som van een rij sum([],R) :- R = 0. sum([X],R) :- R = X. sum([L|List], R) :- sum(List, Recur), R is Recur + L. %alle knopen van de graaf knopen(Result) :- findall(X,(boog(_,X,_);boog(X,_,_)),Knopen), list_to_set(Knopen,Result). %permutates the list permu([],[]). permu(X,[Y|Ys]) :- del(Y,X,Rs), permu(Rs,Ys). %deletes X from the list del(X,[X|Xs],Xs). del(X,[Y|Ys],[Y|Zs]) :- del(X,Ys,Zs).
Een alternatief
boog(a,b,1). boog(a,c,1). boog(b,c,1). boog(c,z,3). boog(b,z,1). mincut(X,Y) :- findall((Opl,L),oplossingen([a],Opl,L),Rij), sort(Rij,Sorted), last(Sorted,Last), neem_minimum(Sorted,Last,(L,Y)), alle_knopen(All), vind_rechterdeel(All,L,[],R), X = (L,R). neem_minimum([],Res,Res). neem_minimum([(Links,Som)|Xs],(LL,SS),(Lres,Sres)) :- ( Som < SS -> neem_minimum(Xs,(Links,Som),(Lres,Sres)) ; neem_minimum(Xs,(LL,SS),(Lres,Sres))). is_bereikbaar(X,Rij,Return) :- findall(B,(boog(X,B),\+ member(B,Rij)),R), delete(R,z,Return). alle_knopen(Result) :- findall(X,boog(X,_,_),Rij1), findall(Y,boog(_,Y,_),Rij2), append(Rij1,Rij2,Rij), sort(Rij,Result). % Alle knopen, Linkerdeel, res en res vind_rechterdeel([],_,Res,Res). vind_rechterdeel([X|Rest],Rij,Res,Result) :- ( member(X,Rij) -> vind_rechterdeel(Rest,Rij,Res,Result) ; vind_rechterdeel(Rest,Rij,[X|Res],Result)). som_rij([],Res,Res). som_rij([X|Xs],SubRes,Res) :- NSubRes is SubRes + X, som_rij(Xs,NSubRes,Res). % Linkerdeel, rechterdeel, result bereken_som(Links,Rechts,Som) :- findall(L,(boog(X,Y,L),member(X,Links),member(Y,Rechts)),Rij), som_rij(Rij,0,Som). % Je zit in, linkerdeel, result oplossingen(Res,Res,Som) :- alle_knopen(Knopen), vind_rechterdeel(Knopen,Res,[],Rechts), bereken_som(Res,Rechts,Som). oplossingen(Rij,Result,L) :- member(M,Rij), boog(M,B,_), B \== z, \+ member(B,Rij), append(Rij,[B],Verder), oplossingen(Verder,Result,L).
--Beau 15 jun 2006 11:51 (CEST)
Een ander alternatief
Elfangor
buur(X,Y,N) :- (boog(X,Y,N) ; boog(Y,X,N)). find(X,Y,snede([X|Z],[Y|W])) :- findall(A,buur(A,_,_),L), list_to_set(L,La), permutation(La,R), append([[X,Y],Z,W],R). mincut(X,Y) :- findall(C-B,(find(a,b,B), capaciteit(B,C)),L), keysort(L,[Xs-_|R]), partition(gelijk(Xs),R,Gelijken,_), pairs_values(Gelijken,Values), findall(C-B,(member(B,Values), gesneden_bogen(B,C)),A), keysort(A,[X-Y|_]). gelijk(Xs,Xs-_). capaciteit(snede(Xs,Ys), C) :- findall(N, (member(X,Xs), member(Y,Ys), buur(X,Y,N)),L), sumlist(L,C). gesneden_bogen(snede(Xs,Ys), C) :- findall(N, (member(X,Xs), member(Y,Ys), buur(X,Y,N)),L), length(L,C).
Een alternatief dat gebruik maakt van een bekend universeel zoekalgoritme
--Nick.dewaele (overleg) 16 jan 2018 19:49 (CET)
boog(a,b,1). boog(a,c,1). boog(b,d,1). boog(c,d,1). boog(d,z,2). neighbor(X, Y) :- boog(X,Y,_); boog(Y, X, _). vertices(V) :- findall(X, neighbor(X, _), Xs), sort(Xs, V). edges(E) :- findall(e(X,Y,W), boog(X,Y,W), E). weight(e(_,_,W), W). % Dit predicaat vindt alle bogen tussen knopen uit V en knopen uit W edgesbetween(V, W, Res) :- findall(e(X,Y,Weight), ( (member(X, V), member(Y, W) ; member(Y,V), member(X, W) ), boog(X,Y,Weight) ), Res). sumWeightEdges(V, W, Sum) :- edgesbetween(V, W, E), maplist(weight, E, Weights), % dit is de "map" van Haskell sum_list(Weights, Sum). mincut(X,Y) :- vertices(Vert), findall(V, (member(V, Vert), \+member(V,[a,z])), InternalNodes), sumWeightEdges([a], [z], InitCost), dijkstra([InitCost-state([a], [z], InternalNodes)], X-Y). dijkstra([Cost-state(Left,Right,[V|Unassigned]) | Q], Res) :- % voeg eerst toe aan de linkerkant sumWeightEdges([V], Right, SL), CostL is Cost + SL, LeftChild = CostL-state([V|Left], Right, Unassigned), % en dan rechts sumWeightEdges([V], Left, SR), CostR is Cost + SR, RightChild = CostR-state(Left, [V|Right], Unassigned), insertPQ([LeftChild, RightChild], Q, NewQ), dijkstra(NewQ, Res). dijkstra([Cost-state(Left, Right, [])|Q], Cost-cut(L,R)) :- % De eerste op de wachtrij is nu optimaal. Als er andere doelen zijn met dezelfde kost, % dan staan die nu ook op de wachtrij. Dit is altijd het geval tenzij er bogen zijn met % gewicht 0. Ik veronderstel dat dit zich nooit voordoet. filterbest([Cost-state(Left, Right, [])|Q], OptStates), include(isGoal, OptStates, OptGoals), % dit is de "filter" van Haskell % geef 1 van de mogelijke resultaten terug. member(_-state(L,R,_), OptGoals). insertPQ(Elems, Q, NewQ) :- append(Elems, Q, Q_), sort(1, @=<, Q_, NewQ). isGoal(_-state(_,_,[])). % haal de knopen uit de (gesorteerde) wachtrij die evenveel kosten als de eerste filterbest([K-V | T], Res) :- filterbest([K-V|T], K, Res). filterbest([K-V | T], K, [K-V|Res]) :- filterbest(T, K, Res). filterbest([K-_ | _], X, []) :- K \= X. filterbest([], _, []). kleinste_mincut(X, Y) :- findall(NumEdges-Cost-cut(Left,Right), ( mincut(Cost, cut(Left,Right)), edgesbetween(Left, Right, E), length(E, NumEdges) ), MinCuts), sort(1, @=<, MinCuts, Sorted), filterbest(Sorted, Best), % kies 1 oplossing member(_-X-Y, Best).