Matematické Fórum

Nevíte-li si rady s jakýmkoliv matematickým problémem, toto místo je pro vás jako dělané.

Nástěnka
22. 8. 2021 (L) Přecházíme zpět na doménu forum.matweb.cz!
04.11.2016 (Jel.) Čtete, prosím, před vložení dotazu, děkuji!
23.10.2013 (Jel.) Zkuste před zadáním dotazu použít některý z online-nástrojů, konzultovat použití můžete v sekci CAS.

Nejste přihlášen(a). Přihlásit

#1 30. 03. 2013 19:09 — Editoval Akcope (30. 03. 2013 19:12)

Akcope
Příspěvky: 109
Reputace:   
 

Vlk, koza, zelí (Pascal)

Ahoj, pokouším se o napsání programu, řešící backtrackingem následující problém, nicméně jsem se v programu zamotal, a prožil dost chvilek beznaděje.

Problém zní následovně : Řeka. Na jednom břehu je pasáček ovcí, vlk, koza, zelí a lodička. Vlk by rád sežral kozu, koza si dělá zálusk na zelí. Do lodičky může pasáček vzít jen jedno zvíře nebo zelí. Dvě zvířata nebo zvíře a zelí se na lodičku najednou nevejdou. Koza ani vlk pádlovat překvapivě neumí.
Jak dostane pasáček vlka, kozu i zelí na druhou stranu tak, aby na jednom břehu nikdy nebyla koza s vlkem nebo se zelím bez dohledu pasáčka?

Snažil jsem se to řešit přes stavový strom, řádně okomentovaný kód viz níže :
________________________________________________________________________________

program vkz_podruhe;
uses crt;
type uprvek = ^prvek;     //lineární spojový seznam - pokud jsme stav už prošli, uloží se do něj v tomto tvaru
     prvek=record
     stav:array[1..4] of integer;
     je_pripustne:boolean;
     dalsi:uprvek;
     end;

var
stav:array[1..4] of integer; //0 - levy breh, 1 - pravy breh... 1. vlk 2.koza 3.zeli 4. prevoznik
hlava:uprvek;
zarazka:uprvek;
novy:uprvek;
cache:record                //pokud funkce "najdi" v seznamu prvek našla, uloží ho sem
     stav:array[1..4] of integer;
     je_pripustne:boolean;
     end;

procedure init();           //nacte seznam
var i:integer;
begin
  for i:=1 to 4 do stav[i] := 0;
  new(hlava);
  new(zarazka);
  hlava^.dalsi := zarazka;
  zarazka^.dalsi := nil;
end;
procedure vloz(vlk:integer;koza:integer;zeli:integer;prevoznik:integer;pripustnost:boolean); //vlozi prvek do seznamu
var pom:uprvek;
begin
  new(novy);
  pom := hlava^.dalsi;
  hlava^.dalsi := novy;
  novy^.dalsi := pom;
  novy^.stav[1] := vlk;
  novy^.stav[2] := koza;
  novy^.stav[3] := zeli;
  novy^.stav[4] := prevoznik;
  novy^.je_pripustne := pripustnost;
end;
function najdi(vlk:integer;koza:integer;zeli:integer;prevoznik:integer):boolean;    //pokud se prvek v seznamu nachází, hodí true a uloží ho do proměnné "cache" pokud ne, hodí false
var pom:uprvek;
begin
  pom := hlava^.dalsi;
  if hlava^.dalsi <> zarazka then begin
     while pom^.dalsi <> zarazka do begin
      if pom^.stav[1] = vlk then if pom^.stav[2] = koza then if pom^.stav[3] = zeli then if pom^.stav[4] = prevoznik then begin
       najdi := true;
       cache.stav[1] := vlk;
       cache.stav[2] := koza;
       cache.stav[3] := zeli;
       cache.stav[4] := prevoznik;
       cache.je_pripustne := pom^.je_pripustne;
      end else
      najdi := false;
    end;
  end else najdi := false;
end;
function presun(co:integer):integer;
begin
if co = 1 then presun := 0;
if co = 0 then presun := 1;
end;
procedure endcheck(vlk:integer;koza:integer;zeli:integer;prevoznik:integer);  //jsme v cíli?
begin
    if vlk=1 then if koza=1 then if zeli=1 then if prevoznik = 1 then begin
     repeat until keypressed;
     halt;
     end;
end;

procedure vkz(vlk:integer;koza:integer;zeli:integer;prevoznik:integer);
var vkzb:boolean; //sezerou se?
    vysledek_hledani:Boolean; [b]//pomocná proměnná, říkající nám výsledek funkce "najdi" abychom nemuseli procházet seznam víckrát[/b]
begin
   writeln(vlk,' ',koza,' ',zeli,' ',prevoznik);
   endcheck(vlk,koza,zeli,prevoznik); //ověřujeme, jestli jsme v cíli
  vkzb:= true;
  if (vlk = 1) and (koza = 1) and (prevoznik = 0) then vkzb := false;
  if (koza = 1) and (zeli = 1) and (prevoznik = 0) then vkzb := false;
  if (vlk = 0) and (koza = 0) and (prevoznik = 1) then vkzb := false;
  if (koza = 0) and (zeli = 0) and (prevoznik = 1) then vkzb := false;    //overujeme jestli je tento stav pripustny

  if najdi(vlk,koza,zeli,prevoznik) = false then begin //tato podmínka prohledá seznám a zjistí, jestli jsme tento stav už prošli
  vloz(vlk,koza,zeli,prevoznik,vkzb);
  vysledek_hledani:= false;
  end else
  vysledek_Hledani:= true;

  if vysledek_hledani = false then if vkzb = true then begin    //pokud jsme tento stav ještě neprošli, a je přípustným částečným řešením, začneme rekurzivně zkoumat jeho podstavy
     vkz(presun(vlk),koza,zeli,presun(prevoznik));
     vkz(vlk,presun(koza),zeli,presun(prevoznik));
     vkz(vlk,koza,presun(zeli),presun(prevoznik));
     vkz(vlk,koza,zeli,presun(prevoznik));
    end else
    if cache.je_pripustne = true then begin        //pokud jsme tento stav už prošli, a je přípustným částečným řešením, rekurzivně zkoumáme jeho podstavy
     vkz(presun(vlk),koza,zeli,presun(prevoznik));
     vkz(vlk,presun(koza),zeli,presun(prevoznik));
     vkz(vlk,koza,presun(zeli),presun(prevoznik));
     vkz(vlk,koza,zeli,presun(prevoznik));
    end else  //zde nevím, jak pokračovat   //pokud jsme tento stav už prošli, a není přípustným částečným řešením,backtrackujeme
end;
begin
  init;
  vkz(0,0,0,0);
  repeat until keypressed;
end.
__________________________________________________________________________________

Teoreticky sice úlohu znám, ale dát to do kódu je už horší. Rád bych, kdyby mi někdo poradil, jak toto dokončit. Popř, jak na to jít znova od začátku, byl bych moc vděčný. Díky.

Offline

 

Zápatí

Powered by PunBB
© Copyright 2002–2005 Rickard Andersson