Algoritamske strategije - backtracking



Backtracking (traganje sa vraćanjem)

1.

Problem: zadata je tablica za igru iks– oks na kojoj su već odigrani neki potezi. Treba utvrditi koji igrač ima strategiju koja vodi do pobede, te koji potez je optimalan potez igrača koji je na redu – na koje polje treba staviti svoju oznaku da bi pobedio ako je to moguće ili odigrao nerešeno ako je moguće

Neka je na potezu igrač “x”. Ako postoji način da on pobedi, toj situaciji se dodeli oznaka 1. Ako ne može pobediti, ali može igrati nerešeno, situacija se označava sa 0, a ako gubi kako god igrao situacija se označava sa -1

Slično, ako je na potezu “o”, situacija u kojoj on može pobediti se označava sa -1, kada može igrati najviše izjednačeno sa 0 i kada gubi sa 1

Primer: zadata je ovakva situacija:


Na potezu je IKS, ima tri polja na koja može igrati.


Dobije se stablo situacija:

levo dete trivijalno ima oznaku 1, jer je pobeda za x.

Za ostalu decu se još ne znaju oznake, ali se zna da koren ima oznaku 1, jer je x na potezu i može pobediti





Ako x ne odigra svoj pobednički potez, moguće su ove situacije:

1. Desno dete je dobilo oznaku 0, jer je na potezu o i ako on odigra prvi potez, rezultat je nerešen, ako odigra drugi, pobeđuje x

2. Srednje dete dobija oznaku -1, jer zavisno od toga šta igra o, onda x gubi ili igra nerešeno


Iz ovog je jasno da je oznaka svakog čvora u kojem je na potezu “o” jednaka minimumu svih oznaka dece tog čvora i analogno ako je na potezu “x” oznaka čvora je maksimum svih oznaka dece čvora
Dakle, algoritam rešavanja je: da bi se odredilo ko u zadatoj situaciji pobeđuje treba kreirati stablo svih situacija dostižljivih iz zadate situacije; koren stabla je zadata situacija, a deca svakog čvora su situacije do kojih se dolazi u jednom potezu iz tog čvora
Težina utvrđivanja pobednika pada što je nivo čvora u stablu veći
Listovi stabla su trivijalne situacije – završetak igre
Za utvrđivanje oznake u čvoru u kojem je na potezu “x” potrebno je naći maksimum svih oznaka dece tog čvora;
za određivanje oznake kad je na potezu “o” potrebno je naći minimum svih oznaka dece tog čvora
Konstrukcija takvog stabla se moze obaviti rekurzivnim algoritmom ciji pseudo-kod je:


ulazne promenljive su:

tablica T– delimično popunjeno polje za igru

na_potezu – oznaka igrača koji je na potezu

izlazna promenljiva je:

igrati – optimalan potez kojeg igrač na potezu može odigrati i funkcija vraća oznaku čvora u stablu koji odgovara tablici T

int IKSOKS(tablica T, char na_potezu, potez *igrati) {

tablica dete;

potez ptemp;

int vrednost_deteta, temp;

if (T je list)

/* tablica je puna, funkcija pobednik() vraća 1 ako pobeđuje x, */ return pobednik(T);

/* 0 za nerešeno, -1 za pobedu o */

else {

if (na_potezu == ‘x’)

vrednost_deteta = -beskonačno;

else

vrednost_deteta = +beskonačno;

za svaki legalan potez move u tablici T radi {

if (na_potezu == ‘x’) {

dete = T + na mestu move je stavljen ‘x’;

temp = IKSOKS(dete, ‘o’, &ptemp);

if (temp > vrednost_deteta) {

vrednost_deteta = temp;

*igrati = move;

}

}



2.

Konstruisati algoritam koji za datu sumu S i dati niz v koji sadrzi vrednosti novcanica pronalazi sva resenja za rasitnjavanja sume S. Pretpostaviti da svake novcanice ima proizvoljno mnogo.

U cemu je razlika ovog zadataka i zadatka resavanog tehnikom pohlepnog algoritma?

#include <stdio.h>

int s; /* novcani iznos koji treba razbiti */

int n; /* broj razlicitih novcanica */

int v[10]; /* vrednosti novcanica/apoena */

int x[10]; /* kolicina pojedinih apoena */


void pisi()

{ int i;

printf("\nRazmena: \n");

for(i=0; i<n; i++) printf("%d dinara:%d puta ", v[i],x[i]);

printf("\n");

}


void razmeni(int k, int s)

{

//k= redni broj apoena

//s = tekuca suma za rasitnjavanje

int i;

if(k>=n)

{ if(s==0) pisi();}

else

for(i=0; i<=s/v[k];i++)

{ x[k]=i;

razmeni(k+1, s -i*v[k]);

}

}


main()

{

int i;

printf("Unesite sumu i broj novcanica\n");

scanf("%d%d",&s,&n);

printf("\nUnesite vrednost za %d novcanica\n",n);

for(i=0; i<n;i++) scanf("%d",&v[i]);

razmeni(0,s);

}

3. Za n studenata i n studentkinja jednog fakulteta dati su podaci o ukupnom broju osvojenih poena na kvalifikacionom testu za kviz. Odrediti sto je moguce vise parova koji se mogu formirati unutar fakulteta i prijaviti za kviz parova ako svaki par cine po jedna studentkinja i jedan student i ako razlika u broju poena kod svkog para ne sme da predje dati broj p.

4. Dat je niz celih brojeva a[0]...a[n-1] i ceo broj S. Konstruisati algoritam koji postavlja operatore + - * / u izrazu (...(a[0]?a[1])?a[2])...)?a[n-1] tako da vrednost izraza bude S. Naci sva resenja.

Dat je pseudo-kod (bez f-je ispisa). Napisite je sami !!!


int s; /* vrednost izraza */

int n; /* broj operanada */

int jeste; /*indikator 0/1 da li vrednost izraza je s*/

int a[50]; /* vrednosti operanada izraza */

int z[50]; /* niz operatora izraza */


void racunaj(int k, int ts)

{

//k= redni broj primenjen operacije

//ts = tekuca suma izraza

if(k==n-1)

{ if(ts==s) {pisi(); jeste=1;} }

else

{ /*formiranje operatora unutar izraza */

z[k]='+'; racunaj(k+1, ts+a[k+1]);

z[k]='-'; racunaj(k+1, ts-a[k+1]);

z[k]='*'; racunaj(k+1, ts*a[k+1]);

if(a[k+1]!=0)

{z[k]='/'; racunaj(k+1, ts/a[k+1]); }

}


}


main()

{

int i;

printf("Unesite vrednost izraza i broj operanada izraza\n");

scanf("%d%d",&s,&n);

printf("\nUnesite vrednost za %d operanada\n",n);

for(i=0; i<n;i++) scanf("%d",&a[i]);

jeste=0;

racunaj(0,a[0]);

if (!jeste) printf("\nNema resenja\n");

}