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;
}