Sei sulla pagina 1di 52

2.

RECURSIVE AND NONRECURSIVE PROGRAMMING


METHODS
Course 2 English classes

Overview
2.1. BACKTRACKING METHOD
2.2. DIVIDE ET IMPERA METHOD

2.1. BACKTRACKING METHOD


There are applications that will determine the
configuration of an input data set that will
maximize or minimize a certain function.
This mechanism involves optimization
problems, and the function is named,
objective or criteria function.

A first mechanism to solve such a problem will consider


all possible combinations of candidates, criteria function
evaluation for each combination till an acceptable
combination will be found.

This method is a brute force mechanism. In this case:

a brute force algorithm will need an exponential computing time


in many cases such an algorithm is not possible to be considered
because we have a huge amount of combinations

An algorithm from this category may be optimized if it is


possible to find specific rules that:

will allow to select combinations that will be first evaluated


will allow to eliminate some combinations that will not be
evaluated

Other approach will consider constraints to reduce the


number of combinations for the evaluation of the criteria
function
The backtracking method belongs to this category
being a refinement of the brute force method

In standard backtracking method, the solution is


represented as a vector (one dimensional array) X:
X(x1, x2,, xn) S=S1xS2xxSn
where:

S is the possible solution space that is finite (Cartesian product of


Si)
xi, i=1,...n, are components of solution S, with values in Si

In backtracking we fast generate a complete solution and


after that we come back on the same trace and we
generate other solutions
The backtracking solutions must satisfy some constraints:

explicit rules that restraints the values set for each component
implicit rules that determines which combinations from the
solution space satisfies the criteria function
6

Characteristics:

The final solution is generated in a sequential mode, component


by component;
We start with an empty vector and at each step we extend the
partial vector with a value (element) to the new component;
The adding process of an element to a component is realized by
evaluating the criteria function to decide if the incomplete (partial)
solution could be considered for a final solution, than we decide to
keep or eliminate the element;
If the added element will generate a valid possible solution, we
pass to the next component;
If the added element will not generate a possible solution, the
element is ignored and we choose another value from the possible
values for that component; In this mode we generate a final
solution.
When all possible values able to be associated to a component
are finished (including for the last component) we come back to
the previous component, and a new value from the value space is
used to generate a possible solution;
If in this come back we arrive at the first component and if no
possible values are able to be considered, the process will be
7
stopped;

In the recursive and iterative standard solution initially we


determine (read) data concerning:

Number of components, n;
Space values dimension, h;
Other data necessary to elaborate the algorithm

In C/C++ implementation we consider a standard solution


as a vector stored in an one dimensional array X(x0, x1,,
xn-1) where:
xk, k=0, ,n-1 is a component and each
component values are in the values space domain:
xk=1,,h,

So each solution is composed by n components 0,...,n-1, each


component with values in the range 1,...,h.

The aim of the method is to generate all possible


solutions
Usual are used recursive functions:

Each instance will manage a component and will process all


possible values keeping the consistent value for the next recursive
call

We have non-recursive (iterative) solutions for the same


problem.
At any backtracking problem we establish:
1. k = 0,,n-1, the number of components of a solution;
2. x[k]=1,,h, possible values for a component;
3. posibil(k), continuity condition.
9

10

Non-recursive, iterative solution


//init step and component value solution
k = 0;
x[k] = 0;
// repeat till more components exists
do {
//till more values for the component
while ( x[k] < h )
{
// pass to the next value
x[k] = x[k]+1;

11

//if the partial solution is possible


if (posibil(k))
{
// if we have a complete solution - ready solution
if ( k==n-1)
afiseaza_solutia(X);
else {
// pass to the next component
k = k+1;
x[k] = 0;
}
}
}//while
k = k-1;
// come back (previous component)
} while(! k<0); // (k>=0) no more components
12

Recursive solution
void Backtracking(int k)
{
// for all posible values of component xk
for(int i=1; i <= h; i++)
{
x[k] = i;
// if the partial solution is possible
if ( posibil(k)) {
// if ready solution
if ( k == n-1)
afiseaza_solutia(X);
else
Backtracking(k+1); // recursive call
}
}
}
13

In main( ):
// init
Backtracking(0);

posibil( ) function will give the continuity condition (intern


condition) that will establish the relations that will be
respected among components of the solution and will
return:

TRUE, if the partial solution is correct and possible;


FALSE, contrary

14

We have variants of backtracking where the solutions are


of different length (variable no. of components), or it is
asked an optimal solution, etc.
Examples:
1. Flag problem
2. Decompose a natural number n, in a sum of natural
numbers (variable length of components)
3. Sales man (optimal solution)

15

Flag problem iterative solution


#include <stdio.h>
#define DIM 5

int posibil(int);
void afis_sol(void);
int x[DIM],n;
void main(void)
{
int k,h;
printf("\nIntrodu numarul de culori ale unui drapel(benzi,
<=DIM=5)\n");
scanf("%d",&n);
printf("Introdu numarul maxim de culori posibile ale unei
benzi \n");
scanf("%d",&h);

16

k=0;
x[k]=0;
do
{
while(x[k] < h) // mai sunt valori posibile pentru
// componenta k
{
x[k]++; //trec la urmatoarea valoare
if(posibil(k))
if(k==(n-1)) afis_sol(); //e gata solutie
else {k++; x[k]=0; }
// trec la urmatoarea
// componenta cu
// valori de la zero
}//while
k--; // nu mai sunt valori pentru componenta k. Revin la
// componenta k-1
}while(!(k<0));
// m-am intors mai mult decit se putea,
// sau k>=0
}//main
17

int posibil(int k)
{
if(k==0)return 1;
if(x[k-1]==x[k]) return 0;

return 1;
}//posibil

//initial totul este posibil


// doua culori alaturate
// identice - nu e posibil
//culorile alaturate nu sunt identice

void afis_sol(void)
{
for(int i=0;i<n;i++)

//afisez solutia curenta pentru


// componentele drapelului
printf("%d ",x[i]);
printf("\n");
}//afis_sol
18

Flag problem recursive solution


#include <stdio.h>
#define DIM 5
int posibil(int);
void afis_sol(void);`
void dr_rec(int k);
int x[DIM],n;
int h;
void main(void)
{
printf("\nIntrodu numarul de culori ale unui drapel(benzi,
<=DIM=5)\n");
scanf("%d",&n);
printf("Introdu numarul maxim de culori posibile ale unei
benzi \n");
scanf("%d",&h);
dr_rec(0); //apel functie recursiva
}//main

19

void dr_rec(int k)
{
for(int i=1;i<=h;i++)
{ x[k]=i;
if(posibil(k))
if(k==(n-1)) afis_sol(); //solutie finala
else dr_rec(k+1); //trec la urmatoarea
//componenta
}
}//dr_rec

Obs! Funciile posibil() i afis_sol() sunt identice cu cele de


la varianta nerecursiv

20

Decompose a natural number n, in a sum of


natural numbers (variable length of
components) iterative solution
#define DIM 20
int Posibil(int k, int &s);
void Afis_sol(int k);
int x[DIM], n;
void main(void)
{
int k,sum;
printf("\nNumarul ce va fi descompus( <=DIM=20) : ");
scanf("%d",&n);
printf("\n\tSolutii posibile :\n");
// initializari
k = 0;
x[k] = 0;

21

do {
while(x[k] < n)
{
x[k]++;
if(Posibil(k, sum)) {
if(sum == n) // solutia finala
Afis_sol(k);
else {
k++;
x[k] = 0;
}
}
} // bucla valori componenta
k--; // pas inapoi
} while(!(k < 0)); // bucla componente
}
22

Decompose a natural number n, in a sum of


natural numbers (variable length of
components) recursive solution
#include <stdio.h>
#define DIM 20
void Back_SubSet(int n);
int Posibil(int k, int &s);
void Afis_sol(int k);
int x[DIM], n;
void main(void)
{
printf("\nNumarul ce va fi descompus( <=DIM=20) : ");
scanf("%d",&n);
printf("\n\tSolutii posibile :\n");
Back_SubSet(0); // apel initial
}

23

void Back_SubSet(int k)
{
int sum;
x[k] = 0;
// pentru toate valorile pe care le poate lua x[k]
while(x[k] < n)
{
x[k]++;
if(Posibil(k, sum))
// solutie posibila
{
if(sum == n)
// solutie completa
Afis_sol(k);
else
Back_SubSet(k+1);
}
}
}

24

int Posibil(int k, int &s)


{
s=0;
if(k==0) return 1;
// initial totul este posibil
if(x[k] > x[k-1]) {
for( int i=0; i<=k; i++)
s += x[i];
if(s <= n)
return 1;
}
return 0;
}
void Afis_sol(int k)
{
printf("\n\t");
for(int i=0; i<=k; i++)
printf("%d ", x[i]);
}

25

Sales man - Comis voiajorul varianta recursiv


/*n orase intre care pot exista legaturi directe cu un cost dat in
COST[n][n], daca nu, e 0. Pornind din orasul i sa se
determine ruta pe care o foloseste pentru a merge doar o
data in cele n orase cu cost minim si a reveni */
#include <stdio.h>
#include <conio.h>
#define MAX 7
void gene(int k);
//metoda recursiva
void cit(int [][MAX],int &);
void afis(int [][MAX],int &);
int max_cost(int [][MAX],int &);
void afis_sol(long &);
int posibil(int);
int x[MAX],Y[MAX];
//x componentele solutiei, rezultatul Y
int COST[MAX][MAX];
int n;
long cost_M,C;

26

void main(void)
{
int k;
printf("Introdu dim matrice costuri(nr.orase) <=7\n");
scanf("%d",&n);
printf("Introdu si afis matricea costurilor C\n");
cit(COST,n);
afis(COST,n);
cost_M=(n+1)*(long)max_cost(COST,n)+1;
// printf("Cost maxim= %ld\n",cost_M);
k=0;
printf("Introdu orasul initial (0 ~ n-1)");
scanf("%d",&x[k]);
gene(1);
afis_sol(cost_M); //e gata solutie
}//main
27

int posibil(int k)
{
if(k==0)return 1;
if(COST[x[k-1]][x[k]]!=0){//drum direct
for(int i=0;i<k;i++)//orasul nu a mai fost ales
if(x[k]==x[i]) return 0;
return 1;
}
return 0;
}//posibil

28

void gene(int k)
{
for(int i=0;i<n;i++)// valori intre 0 si n-1
{
x[k]=i;
if(posibil(k))
if((k==(n-1))&& (COST[x[n-1]][x[0]]!=0)){
C=0;// stabilire cost pentru solutia determinata
for(int i=0;i<n-1;i++) C+=COST[x[i]][x[i+1]];
C+=COST[x[n-1]][x[0]];
if(C<cost_M){
for(int i=0;i<n;i++)
Y[i]=x[i];
cost_M=C; //salvare solutie cost minim
}
}
else gene(k+1);
} //for
} // end gene
29

Conclusions:
The solution is determined by a systematic
search in the solution space
We build the solution vector, component by
component and we test at each step if the
partial obtained vector is able to be
considered in the final solution:
If yes, we continue
If no, the partial obtained vector is ignored

30

Conclusions for backtracking method:


Steps:
Solution vector specifications X[N]:
dimension N,
Elements significance X[i],
Values range for each X[i] component (explicit
constraints),
Starting value a0,
Constraints (implicit) for the solution components

We implement the posibil() function that will


verify the implicit constraints
The method is not usable if the solution vector is
huge and the response time will be also huge
31

Laboratory examples for backtracking:


- colorarea unui drapel cu n benzi, fiecare

band putnd avea h culori


problema damelor de ah: se cere s se
plaseze N dame pe o tabl de ah de
dimensiune NxN, fr s se atace una pe
alta;
problema investirii optime de capital: pentru
un investitor cu un capital C i n oferte la care
trebuie avansate fondurile fi si care aduc
beneficiile bi, se cere selectarea acelor oferte
care i aduc beneficiul maxim;
32

determinarea petelor de culoare de arie maxim


pentru o imagine reprezentat sub forma unei
matrici cu NL linii i NC coloane care conine NG
nuane de gri;
- traseul comis-voiajorului : stabilirea celui mai
scurt traseu fiind date o localitate de pornire, n
localiti ce trebuie vizitate o singur dat,
revenirea fiind obligatorie la localitatea de
pornire (comis voiajor, algoritmul de rutare a
pachetelor Bellman-Ford, Dijkstra).
problema sumei subseturilor: se considera un set
P de n numere pozitive P(p0, p1, ..., pn-1) i M un
numr pozitiv; s se gseasc toate subseturile
lui P pentru care suma numerelor este M;
33

2.2. Divide et impera method


The method comes from real life being
used in the humanity evolution with
different refinements (positive/negative).
Method principle:
Decompose the problem in sub-problems,
in a recursive mode, till a sub-problem may
be solved directly.
sub-problems solutions will be combined to
obtain the final problem solution
34

Binary search
We consider a vector of ordered elements. We
want to find an element (key) from the vector.
We decompose the problem:
We compare the key with the value from the
middle
If are equals, we found the position in the vector
If not, we know which elements (left or right
middle) are used to continue the searching
process
We continue in this mode till we find the
position of the element, or the element is not in
the vector arriving at an empty vector
35

Searching value: 23

36

Searching value : 88

37

The seraching function will return the position from the vector
where is the element, or value (-1) if it is not founded:
int CautareBinara(int *p, int inc, int sfr, int val)//recursive
{
int mij;
mij = (inc + sfr)/2;
if(p[mij] == val)
return mij;

if(inc <= sfr) {


if(p[mij] > val)
sfr = mij - 1;
else
inc = mij + 1;
return CautareBinara(p, inc, sfr, val);
}
return -1;
}

38

Hanoi Tower

We consider 3 rods A, B, C, and n disks of


different diameters, initial all on rod A. Any
disk of smaller diameter will be placed on a
disk with greater diameter.
If we count the disks in ascending mode
considering the diameters, then:
disk 1 has the smallest diameter, next disk 2,
and so, disk n will have the greatest
diameter.
In this mode disk 1 will be on top and disk n
on base.
39

The problem is to move disks from rod A on rod B


respecting the following rules:
At each step only one disk will be moved
Disks will create a descending sequence on
any of the 3 rods, so above disk k we may
position only disks 1, 2, , k-1
rod C will be used as maneuver (handler disk)
Will be determined the number of effectuated
operations
The problem will be solved recursively in 3 steps,
knowing the solution for (n-1) disks
40

Step1: We move disks 1, 2, , n-1 from rod A to


C so:

41

Step2: Disk n is moved from rod A to rod B so:

42

Step3: We move the (n-1) disks from rod C to B


so:

43

Practically, the Hanoi tower problem is


simplified from n disks to same problem for
n-1 disks, that has a solution if we know the
solution for n-2 disks, so and so , till we
solve the problem for n=1
But for n=1, practically we move disk from
source rod A to destination B

44

The 3 rods may be in the following situations:


Source: disks that will be moved on other rod
Destination: the rod where will be the source disks
transferred
Maneuver: the rod used for a temporary handle

The rods aim is changed in the 3 steps of the


moving process
To solve the problem we define a recursive
function:
void hanoi(int n, char a, char b, char c);

int n, no. of disks (numrul de discuri);


char a, source rod (tija surs);
char b, destination rod (tija destinaie);
char c, maneuver rod (tija de manevr).

45

double mutari; // numar de mutari


void hanoi(int n, char a, char b, char c);
void main( )
{
int n;
cout <<"Numarul de discuri este= ";
cin >> n;
mutari = 0;
hanoi(n,'A','B','C');
cout <<"Numarul de mutari este= " << mutari
<<"\n";
}
46

void hanoi(int n, char a, char b, char c)


{
if (n==1) {
printf("Se muta discul 1 de pe tija %c pe tija %c\n",a, b);
mutari++;
getch( );
return;
}
// n>1, Etapa 1, n-1 discuri, a-sursa, c-destinatia, b-manevra
hanoi(n-1, a, c, b);
// Etapa 2, discul n de pe tija a se muta pe b
printf(Se muta discul %d de pe tija %c pe tija %c\n",n, a, b);
mutari++;
getch( );
//Etapa 3, n-1 discuri, c-sursa, b-destinatia, a-manevra
hanoi(n-1,c, b, a);
}

47

Maximum of a vector (one


dimensional array)
Recursive approach:
We decompose the vector in 2 sub-vectors
We determine the maximum for each subvector
We determine the maximum from both
maximum values determined
For each sub-vector we use the same
mechanism till the length of the vector will
be 1
48

The implementation will consider a recursive


function m_max( ):
int m_max(int *vector, int pozi, int len);

The vector is introduced from stdio with function


citire_sir( ), dimension less then a value MAX
The vector will be displayed with the function
tip_sir( )

49

#define MAX 8
void citire_sir(int*, int);
void tip_sir(int*, int);
int m_max(int*, int, int);

void main( )
{
int n, Maxim;
int vect[MAX];
cout << "Numarul de elemente mai mic de " << MAX <<"
este=";
cin >> n;
cout << "Introduceti cele n elemente\n";
citire_sir(vect,n);
Maxim=m_max(vect, 0, n);
cout << "Maximul sirului este " << Maxim <<'\n';
cout <<"Tipareste elementele sirului\n";
tip_sir(vect,n);
}

50

int m_max(int *vector, int pozi, int len)


{
int a,b;
if(len == 1)
return *(vector+pozi);
else
{
a = m_max(vector, pozi, len/2);
b = m_max(vector, len/2+pozi, len/2+len%2);
if(a>b)
return a;
else
return b;
}
}

51

void citire_sir(int* v, int n)


{
// corp functie
}
void tip_sir(int* v, int n)
{
// corp functie
}

52

Potrebbero piacerti anche