Sunteți pe pagina 1din 19

Backtracking

Plusminus

Cerința
Fie n un număr natural.
Să se determine toate posibilitățile de alegere a semnelor + și - pentru care
n = (+|-) 1   + (+|-) 2 + ... + (+|-) n
2 2 2

Date de intrare
Fișierul de intrare plusminus.in conține pe prima linie numărul n.

Date de ieșire
Fișierul de ieșire plusminus.out va conține pe fiecare linie o succesiune
de n semne + sau - , separate prin câte un spațiu, reprezentând câte o soluție a problemei.
Dacă nu există soluție, atunci fișierul de ieșire va conține pe prima linie mesajul IMPOSIBIL.

Restricții și precizări
 1 ≤ n ≤ 23
 șirurile se vor afișa în ordine lexicografica; caracterul - este considerat mai mic decăt
caracterul +

Exemplu
plusminus.in

9
plusminus.out

- - + - + - + + -
+ - - + - - + - +
+ + - - + + - - +
+ + + + - + - - +

Explicație
Sunt 4 posibilități:
1) 9 = -12 – 22 + 32 – 42 + 52 – 62 + 72 + 82 – 92
2) 9 = +12 – 22 – 32 + 42 – 52 – 62 + 72 – 82 + 92
3) 9 = +12 + 22 – 32 – 42 + 52 + 62 – 72 – 82 + 92
4) 9 = +12 + 22 + 32 + 42 – 52 + 62 – 72 – 82 + 92

Rezolvare
#include <fstream>
std::ifstream fin("plusminus.in");
std::ofstream fout("plusminus.out");

int n;
int st[1000];

void tipar(int k)
{
for (int i = 1; i <= n; i++)
if (st[i] == 1)
fout << "- ";
else fout << "+ ";
fout << "\n";
}

void back(int k, int suma)


{
for (int i = 1; i <= 2; i++)
{
st[k] = i;
if (i == 1)
suma -= (k * k);
else suma += (k * k);
if (k <= n)
if (k == n && suma == n) {
tipar(k);
}
else back(k + 1, suma);
if (i == 1)
suma += (k * k);
else suma -= (k * k);
}
}

int main()
{
fin >> n;
if (n % 4 == 0 || (n - 1) % 4 == 0)
back(1, 0);
else
fout << "IMPOSIBIL";
fin.close();
fout.close();
return 0;
}

Sirab

Cerința
Fie S și n două numere naturale nenule.
Să se genereze (în ordine lexicografică) toate şirurile strict crescătoare de n numere
naturale nenule cel mult egale cu S și cu proprietatea că oricare ar fi a şi b două numere
dintr-un astfel de şir a-b divide a+b.

Date de intrare
Fișierul de intrare sirab.in conține pe prima linie două numere naturale S și n, separate
printr-un spațiu.

Date de ieșire
Fișierul de ieșire sirab.out va conține pe fiecare linie câte un șir generat, în ordinea
generării. Numerele din fiecare linie vor fi separate prin câte un spațiu.

Restricții și precizări
 10 ≤ S ≤ 300
 2 ≤ n ≤ 7
 Dacă nu pot fi generate astfel de șiruri atunci se va scrie valoarea 0 în fișierul de
ieșire sirab.out.

Exemplu
sirab.in

10 4

sirab.out

2 3 4 6
3 4 5 6
6 7 8 9
6 8 9 10

Explicație
S=10 și n=4. Se pot genera 4 șiruri strict crescătoare cu proprietatea cerută: (2 3 4 6), (3 4
5 6), (6 7 8 9) și (6 8 9 10).

Rezolvare
#include <fstream>
std::ifstream fin ("sirab.in");
std::ofstream fout ("sirab.out");

int n, vec[20], m;
bool solutie = false;;

bool divid(int a, int b)


{
if(a>0){
if(b%a==0 || a%b==0)
return true;
else return false;
}
return false;
}

bool valid(int k)
{
for(int i=1;i<k;i++)
if(!divid(vec[k]-vec[i],vec[k]+vec[i]) || vec[k] <=vec[i])
return false;
return true;
}

void tipar(int k)
{
solutie = true;
for(int i=1;i<=k;i++)
fout<<vec[i]<<" ";
fout<<"\n";
}

void back(int k)
{
for(int i=1;i<=n;i++)
{
vec[k]=i;
if(valid(k))
{
if(k==m) tipar(k);
else back(k+1);
}
}
}

int main()
{
fin>>n>>m;
back(1);
if(!solutie)
fout<<0;
return 0;
}
Backtracking in plan

Soarece

Cerința
Se dă o tablă dreptunghiulară formată din n linii și m coloane, definind n*m zone, unele dintre
ele fiind libere, altele conținând obstacole. Într-o zonă precizată se află un șoarece care se
poate deplasa pe tablă trecând din zona curentă în zona învecinată cu aceasta pe linie sau
pe coloană. Scopul sau este să ajungă la o bucată de brânză aflată într-o zonă de
asemenea precizată, fără a părăsi tabla, fără a trece prin zone care conțin obstacole și fără
a trece de două ori prin aceeași zonă.
Determinați o modalitate prin care șoarecele poate să ajungă la bucata de brânză.

Date de intrare
Fişierul de intrare soarece1.in conţine pe prima linie numerele n m, separate printr-un
spațiu. Următoarele n linii conțin câte m caractere, care descriu tabla:
caracterul _ corespunde unei zone libere, caracterul # corespunde unei zone ocupate de
obstacol, caracterul S corespunde zonei în care se află șoarecele iar
caracterul B corespunde zonei în care se află bucata de brânză.

Date de ieşire
Fişierul de ieşire soarece1.out va conţine n linii, pe fiecare linie fiind câte m numere, care
descriu traseul șoarecelui, astfel:

 zonelor prin care nu va trece șoarecele le corespund valoarea 0.


 zonei în care se află inițial șoarecele îi corespunde valoarea 1
 următoarei zone din traseul șoarecelui îi corespunde valoarea 2
 fiecărei zone din traseul șoarecelui îi corespunde o valoare număr natural
semnificând la al câtelea pas ajunge șoarecele în acea zonă.

Numerele de pe fiecare linie fișierului de ieșire sunt separate prin exact un spațiu.
Restricţii şi precizări
 1 ≤ n,m ≤ 10
 zona în care se află șoarecele și zona în care se află bucata de brânză sunt libere
 dacă nu există nici modalitate prin care șoarecele va ajunge la bucata de brânză
toate cele n*m numere din fișierul soarece1.out vor fi zero.
 oricare traseu valid al șoarecelui este considerat corect

Exemplu
soarece1.in

6 7
_______
_####B_
____##_
S##_#__
_##_#_#
_______

soarece1.out

0 0 0 0 0 0 0
0 0 0 0 0 14 13
0 0 0 0 0 0 12
1 0 0 0 0 10 11
2 0 0 0 0 9 0
3 4 5 6 7 8 0

Rezolvare
#include <fstream>
std::ifstream fin("soarece.in");
std::ofstream fout("soarece.out");

int n, m, mat[15][15], is, js, ib, jb, nr, k;


struct poz {
int x, y;
}st[150];
void back(int x, int y, int k)
{
if (mat[x][y] == 0)
{
mat[x][y] = 2;
st[k].x = x;
st[k].y = y;
if (x == ib && y == jb)
nr++;
else {
back(x - 1, y, k+1);
back(x, y + 1, k+1);
back(x + 1, y, k+1);
back(x, y - 1, k+1);
}
mat[x][y] = 0;
}
}

int main()
{
fin >> n >> m;
for (int i = 1; i <= n; i++)
mat[i][0] = mat[i][m + 1] = 1;
for (int i = 1; i <= m; i++)
mat[0][i] = mat[n + 1][i] = 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
fin >> mat[i][j];
fin >> is >> js >> ib >> jb;
back(is, js, 1);
fout << nr;
return 0;
}

Saritura_Calului

Cerinţa
Se consideră o tablă de şah cu n linii şi m coloane. La o poziţie dată se află un cal de şah,
acesta putându-se deplasa pe tablă în modul specific acestei piese de şah (în L).
Să se determine o modalitate de parcurgere integrală a tablei de către calul dat, astfel încât
acesta să nu treacă de două ori prin aceeaşi poziţie.
Date de intrare
Programul citește de la tastatură numerele n şi m , apoi numere x y, reprezentând
dimensiunile tablei (numărul de linii şi numărul de coloane) , respectiv coordonatele iniţiale
ale calului (linie, coloana).

Date de ieşire
Programul afișează n linii cu câte m numere naturale cuprinse între 1 și n*m, separate prin
exact un spațiu, reprezentând parcurgerea solicitată.

Restricţii şi precizări
 1 ≤ n,m ≤ 6
 1 ≤ x ≤ n
 1 ≤ y ≤ m
 pentru fiecare dintre testele propuse, există soluție

Exemplu
Date de intrare

4 5 1 1

Date de ieșire

1 12 7 16 3
6 17 2 11 8
13 10 19 4 15
18 5 14 9 20

Rezolvare
#include <iostream>

int n, m, istart, jstart;


int mat[205][205];
bool sol = false;

void tipar()
{
sol = true;
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= m; ++j)
{
std::cout << mat[i][j] << " ";
}
std::cout << "\n";
}
}

void back(int x, int y, int nr)


{
if(!mat[x][y] && !sol)
{
mat[x][y] = nr;
if (nr == n * m)
tipar();
else {
if (2 + x <= n && !sol) {
if (y + 1 <= m && !sol) {
back(2 + x, y + 1, nr + 1);
}
if (y - 1 > 0 && !sol) {
back(2 + x, y - 1, nr + 1);
}
}
if (x - 2 > 0 && !sol) {
if (y + 1 <= m && !sol) {
back(x - 2, y + 1, nr + 1);
}
if (y - 1 > 0 && !sol) {
back(x - 2, y - 1, nr + 1);
}
}
if (2 + y <= m && !sol) {
if (x + 1 <= n && !sol) {
back(1 + x, y + 2, nr + 1);
}
if (x - 1 > 0 && !sol) {
back(x - 1, y + 2, nr + 1);
}
}
if (y - 2 > 0 && !sol) {
if (x + 1 <= n && !sol) {
back(1 + x, y - 2, nr + 1);
}
if (x - 1 > 0 && !sol) {
back(x - 1, y - 2, nr + 1);
}
}
}
mat[x][y] = 0;
}
}

int main()
{
std::cin >> n >> m >> istart >> jstart;
for (int i = 0; i <= n + 2; ++i)
{
mat[i][0] = mat[i][m + 1] = mat[i][m + 2] = 1;
}
for (int i = 0; i <= m + 2; ++i)
{
mat[0][i] = mat[n + 1][i] = mat[n + 2][i] = 1;
}
back(istart, jstart, 1);
return 0;
}
Metoda Greedy

Eureni

Cerința
Pentru cadourile pe care Moş Crăciun urmează să le cumpere copiilor cuminţi, Consiliul
Polului Nord a alocat suma de S eureni. Ştiind că în comerţul polar se utilizează n+1 tipuri de
bancnote de valori 1, e , e , e ,…, e  şi faptul că Moşul trebuie să primească un număr minim
1 2 3 n

de bancnote pentru suma aprobată, să se determine numărul de bancnote din fiecare tip
utilizat în plata sumei şi numărul total de bancnote care i s-au alocat.

Date de intrare
Fișierul de intrare eureni.in conține pe prima linie numerele S n e.

Date de ieșire
Fișierul de ieșire eureni.out va conține mai multe linii: pe fiecare linie va fi scrisă valoare
unei bancnote folosită în plata sumei S și numărul de bancnote folosite, separate printr-un
spațiu, în ordinea descrescătoare a valorilor bancnotelor folosite. Pe ultima linie se va scrie
numai numărul total de bancnote folosite.

Restricții și precizări
 1 < S < 2 000 000 000
 1 < n < 10
 1 < e < 10
 se presupune că există un număr nelimitat de bancnote de fiecare tip

Exemplu
eureni.in
107 4 5

eureni.out

25 4
5 1
1 2
7

Explicație
Sunt 5 tipuri de bancnote, cu valorile: 1, 5, 25, 125, 625 eureni. Pentru a plăti suma
de 107 eureni se folosesc 4 bancnote de 25 eureni, 1 bancnotă de 5 eureni și 2 bancnote
de 1 euren, în total 7 bancnote.

Rezolvare
#include <fstream>
std::ifstream fin ("eureni.in");
std::ofstream fout ("eureni.out");

int s,n,e, maxim_i, sol;


long long vec[15];

int main()
{
fin>>s>>n>>e;
vec[0]=1;
for(int i=1;i<=n;i++){
vec[i]=vec[i-1]*e;
if(vec[i]>s){
maxim_i=i-1;
break;
}else maxim_i=i;
}
while(s)
{
int x = s/vec[maxim_i];
sol+=x;
if(x)
fout<<vec[maxim_i]<<" "<<x<<"\n";
s %= vec[maxim_i];
maxim_i--;
}
fout<<sol;
return 0;
}
Plopi2

Cerinţa
De-a lungul principalei străzi din orașul nostru există n plopi, pentru fiecare cunoscându-se
înălțimea. Primarul orașului dorește ca plopii să aibă înălțimile în ordine descrescătoare.
Pentru aceasta, este posibilă tăierea dintr-un plop a unei bucăți – este o tehnică ecologică,
nevătămătoare, în urma căreia plopul nu are de suferit. Plopii nu pot fi înălțați în niciun fel.
Determinați numărul minim de plopi din care se va tăia și lungimea totală minimă a bucăților
tăiate.

Date de intrare
Fișierul de intrare plopi2.in conține pe prima linie numărul de plopi n. Urmează n numere
naturale nenule, separate prin spaţii, care pot fi dispuse pe mai multe linii, reprezentând
înălțimile plopilor.

Date de ieşire
Fișierul de ieșire plopi2.out va conține pe prima linie numerele C T, separate prin exact
un spațiu, reprezentând numărul minim de plopi din care se va tăia și lungimea totală
minimă a bucăților tăiate.

Restricţii şi precizări
 2 ≤ n ≤ 100
 înălțimile plopilor vor fi mai mici decât 10000

Exemplu
plopi2.in

8
5 7 3 6 4 4 2 6

plopi2.out
5 11

Explicație
Vom tăia din plopii numerotați cu 2 4 5 6 8, astfel încât înălțimile să devină 5 5 3 3 3 3 2
2. Lungimea totală a bucăților tăiate este: 2 + 3 + 1 + 1 +4 = 11

Rezolvare
#include <fstream>
std::ifstream fin ("plopi2.in");
std::ofstream fout ("plopi2.out");

int n, minim;
int plopi[1005];
struct solutie{
int suma, nr;
}sol;

int main()
{
fin>>n;
for(int i=0;i<n;i++)
fin>>plopi[i];
minim = plopi[0];
for(int i=1;i<n;i++)
{
if(plopi[i] > minim)
{
sol.nr++;
sol.suma+=(plopi[i]-minim);
}else minim=plopi[i];
}
fout<<sol.nr<<" "<<sol.suma;
fin.close();
fout.close();
return 0;
}
Programare dinamica

No_pals

Cerința
Gioni este un elev foarte pasionat de informatică și îndrăgește în special problemele care se
rezolvă cu tehnica programării dinamice. El are un număr natural n și vrea să știe pentru
fiecare numar i de la 1 la n câte numere cu i cifre nu sunt palindromuri. Fiindcă acest
număr poate să fie foarte mare, se cere afișarea lui modulo 666013.

Date de intrare
Fișierul de intrare no_pals.in conține pe prima linie numărul n.

Date de ieșire
Fișierul de ieșire no_pals.out va conține pe fiecare linie i, de la 1 la n, numărul de numere
de i cifre care nu sunt palindromuri.

Restricții și precizări
 1 ≤ n ≤ 100000

Exemplu
no_pals.in

no_pals.out

0
81
810

Explicație
Toate numerele de o cifra sunt palindromuri. Sunt 90 de numere de 2 cifre, dintre care 9 sunt
palindromuri. Sunt 900 de numere de 3 cifre, dintre care 90 sunt palindromuri.

Rezolvare
#include <fstream>
std::ifstream fin ("no_pals.in");
std::ofstream fout ("no_pals.out");

int main()
{
unsigned long long n, p = 9, p1 = 9, x=0;
fin >> n;
for (int i = 1; i <= n; i++)
{
if (i % 2 == 1)
{
fout << (x * 10) % 666013 << "\n";
}
else {
x = (p * p1) % 666013;
fout << x << "\n";
p = (p * 10) % 666013;
p1 = (p1 * 10 + 9) % 666013;
}
}
return 0;
}

Rucsac1

Cerința
Într-un magazin sunt n obiecte; pentru fiecare se cunoaște greutatea G și valoarea V. Un hoț
intră în magazin având un rucsac ce poate transporta o greutate maximă GMax. El va fura
anumite obiecte, astfel încât suma greutăților obiectelor furate să nu depășească GMax.
Să se stabilească câștigul maxim pe care îl poate obține hoțul. Câștigul este egal cu suma
valorilor obiectelor furate.

Date de intrare
Programul citește de la tastatură numerele naturale n GMax, iar apoi n perechi de valori G V,
reprezentând greutatea, respectiv valoarea fiecărui obiect.

Date de ieșire
Programul va afișa pe ecran numărul C, reprezentând câștigul maxim pe care îl poate obține
hoțul.

Restricții și precizări
 1 ≤ n ≤ 1.000;
 1 ≤ G, V, GMax ≤ 10.000

Exemplu
Intrare

5 20
2 3
4 5
5 8
3 4
9 10

Ieșire

26

Explicație
Hoțul va lua obiectele 1, 2, 3 și 5, obținând un câștig de 26.
Rezolvare
#include <iostream>
using namespace std;

int mat[1005][10005];
int n, greutate, g, v;

int maxim(int a, int b){return (a > b) ? a : b;}

int main()
{
ios::sync_with_stdio(false);
cin>>n>>greutate;
cin>>g>>v;
for(int i=g;i<=greutate;++i)
mat[1][i] = v;
for(int i=2;i<=n;++i)
{
cin>>g>>v;
for(int j=1;j<=greutate;++j)
{
if(j < g)
{
mat[i][j] = mat[i-1][j];
}else
{
mat[i][j] = maxim(mat[i-1][j], v + mat[i-1][j-g]);
}
}
}
cout<<mat[n][greutate];
return 0;
}

S-ar putea să vă placă și