Binarni nizovi bez dve uzastopne jedinice
Ispiši, u leksikografskom poretku, sve binarne nizove dužine n (n ≤ 15) u kojima nema dve susedne jedinice.
Primer
Ulaz
3Izlaz
000
001
010
100
101Bektreking sistematski isprobava sve mogućnosti, ali se čim primeti da trenutni pokušaj ne može da uspe vraća korak nazad i bira drugu mogućnost. Koristi se za raspoređivanje, slagalice, podskupove i sve zadatke u kojima treba pronaći ili prebrojati rasporede.
Rešenje se gradi korak po korak. U svakom koraku:
Svi izbori zajedno čine stablo pretrage. Bektreking ga obilazi u dubinu, a odsecanje (pruning) preskače grane za koje se unapred zna da ne vode rešenju.
Opšti oblik:
void pretraga(int korak) {
if (rešenje je kompletno) {
obradi rešenje (ispiši, prebroji…);
return;
}
for (svaka mogućnost m za ovaj korak) {
if (m je dozvoljena) { // odsecanje
primeni m; // izaberi
pretraga(korak + 1); // istraži
poništi m; // vrati stanje
}
}
}
Dato je n prirodnih brojeva i broj S. Koliko podskupova ima zbir tačno S? Za svaki broj biramo: uzimamo ga ili ne. Ako je trenutni zbir već veći od S, dalje nema smisla tražiti (brojevi su pozitivni) – to je odsecanje.
#include <iostream>
#include <vector>
using namespace std;
int n, S;
vector<int> a;
int brojResenja = 0;
void pretraga(int i, int zbir) {
if (zbir > S) return; // odsecanje: već smo premašili S
if (i == n) { // odlučili smo za sve brojeve
if (zbir == S) brojResenja++;
return;
}
pretraga(i + 1, zbir + a[i]); // uzimamo a[i]
pretraga(i + 1, zbir); // ne uzimamo a[i]
}
int main() {
cin >> n >> S;
a.resize(n);
for (int &x : a) cin >> x;
pretraga(0, 0);
cout << brojResenja << endl;
return 0;
}
Za 2 3 5 7 8 i S = 10 rešenja su {2, 3, 5}, {2, 8} i {3, 7}. Ovde se stanje ne mora eksplicitno poništavati jer se zbir prenosi kao parametar.
Na tablu N × N treba postaviti N dama tako da se nijedne dve ne napadaju. Dame postavljamo red po red; za svaku kolonu proveravamo da li je ona slobodna i da li su slobodne obe dijagonale. Za zauzetost koristimo tri niza logičkih vrednosti, pa je provera trenutna.
#include <iostream>
using namespace std;
int n, brojRasporeda = 0;
bool kolona[20], diag1[40], diag2[40]; // diag1: r + k, diag2: r - k + n
void postavi(int r) {
if (r == n) { // sve dame su postavljene
brojRasporeda++;
return;
}
for (int k = 0; k < n; k++) {
if (kolona[k] || diag1[r + k] || diag2[r - k + n]) continue; // napadnuto polje
kolona[k] = diag1[r + k] = diag2[r - k + n] = true; // izaberi
postavi(r + 1); // istraži
kolona[k] = diag1[r + k] = diag2[r - k + n] = false; // poništi
}
}
int main() {
cin >> n;
postavi(0);
cout << brojRasporeda << endl;
return 0;
}
Za N = 8 postoji 92 rasporeda. Zadatak sa ispisom rasporeda i detaljnim objašnjenjem: N kraljica – rešenje.
U najgorem slučaju bektreking obilazi celo stablo pretrage, a ono je eksponencijalno veliko (2n podskupova, n! permutacija). Zato se koristi kada je n malo (obično do 20–25 za podskupove, do 10–12 za permutacije) ili kada odsecanje odbacuje veliki deo stabla. Ako se u pretrazi ista stanja ponavljaju, umesto bektrekinga često pomaže dinamičko programiranje.
Za svaki zadatak postoji primer, uputstvo i rešenje. Rešenja su provereno tačna na primerima iz teksta.
Ispiši, u leksikografskom poretku, sve binarne nizove dužine n (n ≤ 15) u kojima nema dve susedne jedinice.
3000
001
010
100
101Lavirint je matrica n × m (n, m ≤ 6) u kojoj . označava prolaz, a # zid. Koliko ima različitih puteva od gornjeg levog do donjeg desnog polja, ako se kreće gore, dole, levo i desno i nijedno polje se ne posećuje dva puta?
3 3
...
.#.
...2Treba podeliti n takmičara (n ≤ 20) sa datim jačinama u dve ekipe tako da razlika zbira jačina bude što manja. Ispiši najmanju razliku.
5
3 1 4 2 20bool).1. Šta znači „poništiti izbor“ u bektrekingu?
2. Koliko čvorova na poslednjem nivou ima stablo pretrage za podskupove skupa od n elemenata?
3. Čemu služi odsecanje?