Note de curs, probleme algoritmică, 9 decembrie 2013
From Algopedia
Jump to navigationJump to search
În acest curs am discutat despre problema 1152 - False Mirrors.
Implementare
Versiunea 1
Să se rezolve problema prin backtracking recursiv, cu variabile globale.
Complexitate timp: O(N! * N)
Complexitate spațiu: O(N)
#include <stdio.h>
const int MAX_N = 20;
const int MAX_INT = 0x7fffffff;
int N;
int V[MAX_N];
bool distrus[MAX_N];
int raspuns;
int backtracking() {
int i, j;
int raspuns = 0x7fffffff;
bool distrusComplet;
distrusComplet = true;
for (i = 0; i < N; ++i) {
if (!distrus[i]) {
distrusComplet = false;
}
}
if (distrusComplet) {
raspuns = 0;
} else {
int lovit;
int raspunsPotential;
for (i = 0; i < N; ++i) {
if (!distrus[i]) {
bool anteriorI = distrus[(i ) % N];
bool anteriorI1 = distrus[(i + 1) % N];
bool anteriorI2 = distrus[(i + 2) % N];
distrus[(i ) % N] = true;
distrus[(i + 1) % N] = true;
distrus[(i + 2) % N] = true;
lovit = 0;
for (j = 0; j < N; ++j) {
if (!distrus[j]) {
lovit += V[j];
}
}
raspunsPotential = lovit + backtracking();
if (raspuns > raspunsPotential) {
raspuns = raspunsPotential;
}
distrus[(i ) % N] = anteriorI;
distrus[(i + 1) % N] = anteriorI1;
distrus[(i + 2) % N] = anteriorI2;
}
}
}
return raspuns;
}
int main(void) {
int i;
// citirea datelor
scanf("%d", &N);
for (i = 0; i < N; ++i) {
scanf("%d", &V[i]);
}
// calcularea solutiei
for (i = 0; i < N; ++i) {
distrus[i] = false;
}
raspuns = backtracking();
// afisarea solutiei
printf("%d\n", raspuns);
return 0;
}
Versiunea 2
Să se rescrie rezolvarea anterioară astfel încât variabila globală bool distrus[MAX_N] să fie înlocuită cu un parametru întreg, folosit pe biți (int distrus).
Complexitate timp: O(N! * N)
Complexitate spațiu: O(N)
#include <stdio.h>
const int MAX_N = 20;
const int MAX_INT = 0x7fffffff;
int N;
int V[MAX_N];
int raspuns;
int backtracking(int distrus) {
int i, j;
int raspuns = 0x7fffffff;
bool distrusComplet;
if (distrus == (1 << N) - 1) {
distrusComplet = true;
} else {
distrusComplet = false;
}
if (distrusComplet) {
raspuns = 0;
} else {
int lovit;
int raspunsPotential;
for (i = 0; i < N; ++i) {
if ((distrus & (1 << i)) == 0) {
int anterior = distrus;
distrus |= 1 << ((i ) % N);
distrus |= 1 << ((i + 1) % N);
distrus |= 1 << ((i + 2) % N);
lovit = 0;
for (j = 0; j < N; ++j) {
if ((distrus & (1 << j)) == 0) {
lovit += V[j];
}
}
raspunsPotential = lovit + backtracking(distrus);
if (raspuns > raspunsPotential) {
raspuns = raspunsPotential;
}
distrus = anterior;
}
}
}
return raspuns;
}
int main(void) {
int i;
// citirea datelor
scanf("%d", &N);
for (i = 0; i < N; ++i) {
scanf("%d", &V[i]);
}
// calcularea solutiei
raspuns = backtracking(0);
// afisarea solutiei
printf("%d\n", raspuns);
return 0;
}
Versiunea 3
Să se rescrie rezolvarea anterioară astfel încât să se optimizeze execuția algoritmului, prin memoizarea funcției recursive.
Complexitate timp: O(N * 2N * N)
Complexitate spațiu: O(N * 2N)
#include <stdio.h>
const int MAX_N = 20;
const int MAX_INT = 0x7fffffff;
int N;
int V[MAX_N];
int raspuns;
int Backtracking[1 << MAX_N];
int backtracking(int distrus) {
if (Backtracking[distrus] == MAX_INT) {
int i, j;
int raspuns = 0x7fffffff;
bool distrusComplet;
if (distrus == (1 << N) - 1) {
distrusComplet = true;
} else {
distrusComplet = false;
}
if (distrusComplet) {
raspuns = 0;
} else {
int lovit;
int raspunsPotential;
for (i = 0; i < N; ++i) {
if ((distrus & (1 << i)) == 0) {
int anterior = distrus;
distrus |= 1 << ((i ) % N);
distrus |= 1 << ((i + 1) % N);
distrus |= 1 << ((i + 2) % N);
lovit = 0;
for (j = 0; j < N; ++j) {
if ((distrus & (1 << j)) == 0) {
lovit += V[j];
}
}
raspunsPotential = lovit + backtracking(distrus);
if (raspuns > raspunsPotential) {
raspuns = raspunsPotential;
}
distrus = anterior;
}
}
}
Backtracking[distrus] = raspuns;
}
return Backtracking[distrus];
}
int main(void) {
int i;
// citirea datelor
scanf("%d", &N);
for (i = 0; i < N; ++i) {
scanf("%d", &V[i]);
}
// calcularea solutiei
raspuns = backtracking(0);
// afisarea solutiei
printf("%d\n", raspuns);
return 0;
}