From: Sasa Tosic Date: Sat, 28 Nov 2015 15:15:54 +0000 (+0100) Subject: Zadatak nalazenje da li postoji put u lavirintu. X-Git-Url: https://svarog.pmf.uns.ac.rs/gitweb/?a=commitdiff_plain;h=d52238cc68af64189464446d81a23aef1469cb99;p=spa2-materijali.git Zadatak nalazenje da li postoji put u lavirintu. Zadatak je predvidjen za prakticne vezbe. Dato je i resenje. --- diff --git a/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/Lavirint.java b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/Lavirint.java new file mode 100644 index 0000000..3dd580f --- /dev/null +++ b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/Lavirint.java @@ -0,0 +1,86 @@ +/** + * Klasa Lavirint sadrzi 2 javne i jednu privatnu metodu za trazenje puteva. + * + */ + +public class Lavirint { + + // Polje m sadrzi kompletnu mapu + private Mapa m; + + // Ucitava mapu iz datog fajla i stampa je na ekran + Lavirint(String imeFajla) { + m = Mapa.ucitajIzFajla(imeFajla); + m.stampaj(); + } + + // Provarava da li postoji put do izlaza i vraca vrednost true + // ako postoji put ili vrednost false ako ne postoji + public boolean postojiPut(int x, int y) { + if (x < 0 || x >= m.getSirina() || y < 0 || y >= m.getVisina()) { + return false; + } + if (m.getPos(x, y) == true) { + return false; + } + if (m.getMat(x, y) == Mapa.ZID) { + return false; + } + if (m.getMat(x, y) == Mapa.IZLAZ) { + return true; + } else { + m.setPos(x, y, true); + if (postojiPut(x + 1, y)) { + return true; + } + if (postojiPut(x - 1, y)) { + return true; + } + if (postojiPut(x, y + 1)) { + return true; + } + if (postojiPut(x, y - 1)) { + return true; + } + m.setPos(x, y, false); + return false; + } + } + + // Poziva metodu rput da pronadje i ispise put, ako postoji + // Ukoliko put ne postoji, ispisuje poruku o gresci + public void nadjiPut(int x, int y) { + if (!rput(x, y)) { + System.err.println("Ne postoji put"); + } + } + + // Proverava da li postoji put korsiteci pretrazivanje sa vracanjem + // Ukoliko se pronadje izlaz iz lavirinta, stampa se put u obrnutom + // redosledu + // Put se stampa pri povratku iz rekurzije + private boolean rput(int x, int y) { + if (x < 0 || x >= m.getSirina() || y < 0 || y >= m.getVisina()) { + return false; + } + if (m.getPos(x, y)) { + return false; + } + if (m.getMat(x, y) == Mapa.ZID) { + return false; + } + if (m.getMat(x, y) == Mapa.IZLAZ) { + System.out.println(x + " " + y); + return true; + } else { + m.setPos(x, y, true); + if (rput(x + 1, y) || rput(x, y + 1) || rput(x, y - 1) + || rput(x - 1, y)) { + System.out.println(x + " " + y); + return true; + } + m.setPos(x, y, false); + return false; + } + } +} diff --git a/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/LavirintProgram.java b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/LavirintProgram.java new file mode 100644 index 0000000..0532130 --- /dev/null +++ b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/LavirintProgram.java @@ -0,0 +1,45 @@ +/** + * Program za nalazenje puta u lavirintu. + * + * Date su dve varijante problema + * + * Jednostavnije je samo nalazenje da li put postoji. + * + * Prosirenje tog resenja nam ispisuje taj nadjeni put. + */ + +public class LavirintProgram { + + public static void main(String[] args) { + Svetovid.out.println("Unesite ime fajla: "); + String fajl = Svetovid.in.readLine(); + if (!Svetovid.testIn(fajl)) { + System.out.println("Greska: nema fajla!"); + return; + } + + Lavirint l = new Lavirint(fajl); + + if (l != null) { + System.out.println("1 - da li postoji put"); + System.out.println("2 - ispis nekog puta (ako postoji)"); + System.out.println("Unesite izbor 1-2:"); + int op = Svetovid.in.readInt(); + + switch (op) { + case 1: + if (l.postojiPut(0, 0)) { + System.out.println("Postoji put"); + } else { + System.out.println("Ne postoji put"); + } + break; + case 2: + l.nadjiPut(0, 0); + break; + default: + System.err.println("Uneli ste pogresan izbor"); + } + } + } +} \ No newline at end of file diff --git a/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/Mapa.java b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/Mapa.java new file mode 100644 index 0000000..a5e8a15 --- /dev/null +++ b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/Mapa.java @@ -0,0 +1,78 @@ +public class Mapa { + public final static int IZLAZ = -99; + public final static int ZID = -11; + public final static int ERROR = Integer.MIN_VALUE; + + private int visina, sirina; + private int[][] mat; + private boolean[][] pos; + + public int getSirina() { + return sirina; + } + + public int getVisina() { + return visina; + } + + public void setPos(int x, int y, boolean b) { + if (0 <= x && x < sirina && 0 <= y && y < visina) { + pos[x][y] = b; + } + } + + public boolean getPos(int x, int y) { + if (0 <= x && x < sirina && 0 <= y && y < visina) { + return pos[x][y]; + } else { + return true; + } + } + + public int getMat(int x, int y) { + if (0 <= x && x < sirina && 0 <= y && y < visina) { + return mat[x][y]; + } else { + return ERROR; + } + } + + public Mapa(int sirina, int visina) { + this.sirina = sirina; + this.visina = visina; + mat = new int[sirina][visina]; + pos = new boolean[sirina][visina]; + } + + public static Mapa ucitajIzFajla(String imeFajla) { + if (!Svetovid.testIn(imeFajla)) { + return null; + } + + int sirina = Svetovid.in(imeFajla).readInt(); + int visina = Svetovid.in(imeFajla).readInt(); + if (sirina >= 0 && visina >= 0) { + Mapa res = new Mapa(sirina, visina); + for (int j = 0; j < visina; j++) + for (int i = 0; i < sirina; i++) + res.mat[i][j] = Svetovid.in(imeFajla).readInt(); + Svetovid.closeIn(imeFajla); + return res; + } else { + Svetovid.closeIn(imeFajla); + return null; + } + } + + public void stampaj() { + if (visina != 0 && sirina != 0) { + System.out.println(visina + " " + sirina); + for (int j = 0; j < visina; j++) { + for (int i = 0; i < sirina; i++) { + System.out.print(mat[i][j] + "\t"); + } + System.out.println(); + } + } + } +} diff --git a/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lav-prepreke.txt b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lav-prepreke.txt new file mode 100644 index 0000000..3839c6d --- /dev/null +++ b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lav-prepreke.txt @@ -0,0 +1,10 @@ +8 8 + 0 2 3 4 6 55 0 -99 + 0 -11 0 -11 7 0 0 0 + 0 -11 0 -11 0 0 -11 0 + 0 0 2 0 -11 0 -11 0 + 0 -11 -11 0 -11 0 -11 0 + 0 -11 0 0 -11 0 -11 0 + 0 -11 -11 0 -11 0 -11 0 + 0 0 44 2 4 0 0 0 + diff --git a/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lav-rupe.txt b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lav-rupe.txt new file mode 100644 index 0000000..a519c68 --- /dev/null +++ b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lav-rupe.txt @@ -0,0 +1,7 @@ +5 6 + 0 -1 0 -11 -99 + 0 -11 0 -11 0 + 0 -11 0 0 0 + 0 -11 0 -11 -1 + -11 -11 -1 -11 -1 + 0 -11 0 0 0 diff --git a/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lav1.txt b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lav1.txt new file mode 100644 index 0000000..70a9571 --- /dev/null +++ b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lav1.txt @@ -0,0 +1,7 @@ +5 6 + 0 0 0 -11 -99 + 0 -11 0 -11 0 + 0 -11 0 0 0 + 0 -11 0 -11 0 + -11 -11 0 0 0 + 0 -11 0 0 -11 diff --git a/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lav2.txt b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lav2.txt new file mode 100644 index 0000000..148f5b5 --- /dev/null +++ b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lav2.txt @@ -0,0 +1,10 @@ +8 8 + 0 0 0 0 0 -11 0 -99 + 0 -11 0 -11 0 0 0 0 + 0 -11 0 -11 0 0 -11 0 + 0 0 0 0 -11 0 -11 0 + 0 -11 -11 0 -11 0 -11 0 + 0 -11 0 0 -11 0 -11 0 + 0 -11 -11 0 -11 0 -11 0 + 0 0 -11 0 0 0 0 0 + diff --git a/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lavb.txt b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lavb.txt new file mode 100644 index 0000000..32632c4 --- /dev/null +++ b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lavb.txt @@ -0,0 +1,7 @@ +5 6 + 0 0 0 -11 -99 + 0 -11 0 -11 0 + 0 -11 0 -11 0 + 0 -11 0 -11 0 +-11 -11 0 0 -11 + 0 -11 0 0 -11 diff --git a/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lavp.txt b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lavp.txt new file mode 100644 index 0000000..0cb506b --- /dev/null +++ b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/lavp.txt @@ -0,0 +1,5 @@ +4 4 + 0 0 0 0 + 0 0 0 0 + 0 0 0 0 + 0 0 0 -99 diff --git a/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/zad-put-u-lavirintu.txt b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/zad-put-u-lavirintu.txt new file mode 100644 index 0000000..66bec95 --- /dev/null +++ b/PretrazivanjeSaVracanjem/Lavirint/PostojanjePuta/zad-put-u-lavirintu.txt @@ -0,0 +1,127 @@ +============================================================ + Zadatak - pretrazivanje sa vracanjem - put u lavirintu +============================================================ + + +Postavka problema +============================================================ + +Neka je dat lavirint kao matrica polja, pri cemu razlicite +vrednosti polja imaju razlicito znacenje. Potrebno je pronaci +put kroz lavirint od pocetnog polja, do izlaza iz lavirinta, +pri cemu se pod putem smatra niz polja koja je potrebno +posetiti u datom redosledu, da bi se stiglo od pocetnog polja +do cilja. Pri obilasku lavirinta, sa jednog polja je moguce +preci na susedno ako ona imaju istu ivicu, tj. ako se ono +nalazi odmah levo, desno, gore ili dole u odnosu na trenutno +polje. + +Znacenja vrednosti polja su; +0 = slobodno polje u lavirintu na koje je dozvoljeno stati +-11 = zid, polje na koje nije dozvoljeno stati +-99 = izlaz iz lavirinta + + +Format fajla +------------------------------------------------------------ + +Mapa je u fajlu predstavljena na sledeci nacin: + +U prvom redu se nalaze dva broja S i V koji predstavljaju +sirinu i visinu mape. + +U sledecih V redova se nalaze po S celih brojeva koji +predstavljaju vrednosti polja u lavirintu. + +Polje (0, 0) nalazi se u gornjem levom polju matrice. + + +Primeri +------------------------------------------------------------ + +Za testiranje programa su dati su fajlovi: +"lav1.txt" i "lav2.txt" u kojima postoji resenje +"lavp.txt" koji ne sadrzi zidove +"lavb.txt" u kojem nije moguce naci resenje + +"lav-rupe.txt" za testiranje modifikacije zadatka sa rupama +"lav-prepreke.txt" za testiranje modifikacije zadatka sa preprekama + +Modifikacije su opisane na kraju teksta. + + +Zadatak +============================================================ + +Napisati klasu LavirintProgram koja ucitava ime fajla u kojem +se nalazi definisan lavirint, koordinate pocetne pozicije +(x, y) od koje se trazi izlaz iz lavirinta, kao i izbor sta +zelimo da radimo. Nakon ucitanog izbora, klasa treba da ucita +lavirint iz datog fajla, ispise ga na ekran i izvrsi izabranu +operaciju. + +Ponuditi korisniku sledeci izbor: +1 - provera da li postoji put od unetog polja do izlaza +2 - ispis puta ukoliko postoji, odnosno ispis poruke da put + ne postoji + + +Pretrazivanje sa vracanjem +------------------------------------------------------------ + +Jedan od nacina da se uradi zadatak je koriscenjem pretrazivanja +sa vracanjem (poznatom u literaturi pod engleskim nazivom +"backtrack"). + +Ideja je jednostavna, krenemo od prvog polja, oznacimo ga +kao poseceno i pokusamo da se prebacimo na bilo koje +neobidjeno susedno. Na tom polju ponovimo isti postupak i +tako nastavljamo dok ne naidjemo na izlaz ili dok vise +nemamo gde da idemo. + +Ukoliko nismo naisli na izlaz, a nemamo gde dalje da idemo, +onda oznacimo trenutno polje kao neobidjeno i vratimo se +jedno polje nazad i probamo nekog drugog suseda. Ako vise +nema suseda vratimo se jos jedno polje. Ukoliko vise nema +gde da se vracamo znaci da se do izlaza ne moze doci. + +Backtrack je najlakse izvoditi rekurzivno, tako da se poziv +procedure vrsi za pojedinacno polje. Ovako se povratkom iz +rekurzije vracamo na polje odakle smo dosli. + + +Jedna od mogucih varijanti ideje procedure: + +rek(i,j,...) +- nije u matrici? -> izlaz +- zid? -> izlaz +- poseceno polje? -> izlaz +- da li je kraj? -> obradimo resenje +- inace trazimo dalje +- postavimo da je poseceno polje +- pokusamo da obidjemo sve susede: +- rek(i+1,j,..) +- rek(i-1,j,..) +- rek(i,j+1,..) +- rek(i,j-1,..) +- postavimo da polje nije poseceno + + +Prosirenje zadatka: +------------------------------------------------------------ + +Neka je dat lavirint sa sledecim dodatnim poljima: +-1 = rupa na putu +bilo koji pozitivan broj = visina prepreke na putu + +Modifikovati postojece metode za trazenje puta tako da: +- omogucavaju preskakanje rupa, ali samo ako je rupa velicine + jednog polja. Rupe koje su u datom pravcu duze od jednog + polja ne preskakati +- omogucava penjanje po preprekama, ali samo po preprekama + koje su za najvise 3 vislje od visine trenutnog polja. + Ukoliko se vec nalazimo na prepreci, dozvoljeno je preci na + vislju prepreku, ukoliko ona nije veca za vise od 3 od + postojece prepreke. Silazak sa prepreke je moguc na bilo + koje polje osim zida +- omogucava preskakanje prepreka, ali najvise 4 puta