Backtracking (visszalépéses keresés)
Feladatmegoldási módszer, leggyakrabban kombinatorikai elemek
generálására vagy ezek közötti keresésre használjuk.
Bevezető feladatok
1. Adott az {1,2,3,4,5} számjegyhalmaz.
Állítsuk elő az összes kétjegyű számot ezekből
(egy elemet lehet többször is használni)!
11
12
13
14
15
21
22
...
53
54
55
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| #include <iostream>
#include <fstream>
using namespace std;
int main()
{
ofstream fout("output.txt");
for (int i = 1; i <= 5; i++)
for (int j = 1; j <= 5; j++)
fout << i << j << endl;
return 0;
}
|
2. Adott az {1,2,3,4,5} számjegyhalmaz.
Állítsuk elő az összes háromjegyű számot ezekből
(egy elemet lehet többször is használni)!
111
112
113
114
115
121
122
123
...
155
211
212
...
555
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| #include <iostream>
#include <fstream>
using namespace std;
int main()
{
ofstream fout("output.txt");
for (int i = 1; i <= 5; i++)
for (int j = 1; j <= 5; j++)
for (int k = 1; k <= 5; k++)
fout << i << j << k << endl;
return 0;
}
|
Descartes-szorzat generálása
3. Adott az {1,2,3,4,5} számjegyhalmaz.
Beolvasunk egy n értéket a felhasználótól,
állítsuk elő az összes n-jegyű számot ezekből
a számjegyekből.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| #include <iostream>
#include <fstream>
using namespace std;
ofstream fout("output.txt");
void f(int szint, int n, int megoldas[])
{
if (szint == n) {
// kiírás
for (int i = 0; i < n; i++)
fout << megoldas[i];
fout << endl;
}
else {
for (int i = 1; i <= 5; i++) {
megoldas[szint] = i;
f(szint+1, n, megoldas);
}
}
}
int main()
{
int n;
cout << "n = ";
cin >> n;
int megoldas[5];
f(0, n, megoldas);
return 0;
}
|
Permutációk
HF: adott n esetén írjuk ki az {1,2,…,n} halmaz összes permutációját!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| #include <iostream>
#include <fstream>
using namespace std;
ofstream fout("output.txt");
void f(int szint, int n, int megoldas[])
{
if (szint == n) {
// kiírás
for (int i = 0; i < n; i++)
fout << megoldas[i] << " ";
fout << endl;
}
else {
for (int i = 1; i <= n; i++) {
bool talalt = false;
for (int k = 0; k < szint; k++)
if (megoldas[k] == i)
talalt = true;
if (!talalt) {
megoldas[szint] = i;
f(szint+1, n, megoldas);
}
}
}
}
int main()
{
int n;
cout << "n = ";
cin >> n;
int megoldas[5];
// lexikografikus sorrendben
// állnak elő
f(0, n, megoldas);
return 0;
}
|
Variációk
HF: Adott n, k.
Írjuk ki az {1,2,…,n} halmaz k-ad
rendű variációit.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
| #include <iostream>
#include <fstream>
using namespace std;
ofstream fout("output.txt");
void f(int szint, int n, int k, int megoldas[])
{
if (szint == k) {
// kiírás
for (int i = 0; i < k; i++)
fout << megoldas[i] << " ";
fout << endl;
}
else {
for (int i = 1; i <= n; i++) {
bool talalt = false;
for (int k = 0; k < szint; k++)
if (megoldas[k] == i)
talalt = true;
if (!talalt) {
megoldas[szint] = i;
f(szint+1, n, k, megoldas);
}
}
}
}
int main()
{
int n, k;
cout << "n = ";
cin >> n;
cout << "k = ";
cin >> k;
int megoldas[5];
// lexikografikus sorrendben
// állnak elő
f(0, n, k, megoldas);
return 0;
}
|
Kombinációk
HF: Adott n, k.
Írjuk ki az {1,2,…,n} halmaz k-ad
rendű kombinációit (mindegyikben legyenek növekvő sorrendben az elemek).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
| #include <iostream>
#include <fstream>
using namespace std;
ofstream fout("output.txt");
void f(int szint, int n, int k, int megoldas[])
{
if (szint == k) {
// kiírás
for (int i = 0; i < k; i++)
fout << megoldas[i] << " ";
fout << endl;
}
else {
for (int i = 1; i <= n; i++) {
if (szint == 0 || i > megoldas[szint-1]) {
megoldas[szint] = i;
f(szint+1, n, k, megoldas);
}
}
}
}
int main()
{
int n, k;
cout << "n = ";
cin >> n;
cout << "k = ";
cin >> k;
int megoldas[5];
// lexikografikus sorrendben
// állnak elő
f(0, n, k, megoldas);
return 0;
}
|
HF
Írjunk programot, ami adott n-re kiírja
az {1,2,…,n} halmaz azon permutációit,
amikben két egymás melletti elem
különbségének modulusza nem nagyobb kettőnél.
HF (+pontért)
Csak akkor jár érte, ha a kötelező is megvan és be tudjátok mutatni a megoldást.
Adott egy S pénzösszeg, majd n darab
bankjegytípus, minden típusú bankjegyből
tetszőleges számút fel tudunk használni.
Írjuk ki az összes kifizetési lehetőségét
az S összegnek (egy lehetőséget mindig
csökkenő sorrendben írunk csak ki).
Példa:
70
3
10 20 50
Kimenet:
50 20
50 10 10
20 20 20 10
20 20 10 10 10
20 10 10 10 10 10
10 10 10 10 10 10 10
HF (+pontért)
Csak akkor jár érte, ha a kötelező is megvan és be tudjátok mutatni a megoldást.
Írjuk ki az összes módját 8 királynő elhelyezésének egy sakktáblán,
ha bármelyik kettő közülük nem ütheti egymást. A kimenet formátuma
tetszőleges, de legyen könnyű értelmezni (pl. rajz vagy oszlopok permutációja).
További feladatok
1. Adott n és k esetén generáljuk az
{1,2,…,n} halmaz azon k-ad rendű variációit és kombinációit
(utóbbinál az elemek növekvő sorrendben kell legyenek),
amelyekben nincs két azonos paritású elem egymás
mellett.
Példa:
n = 5, k = 3
{1,2,3,4,5}
Variációk:
[_] [_] [_]
1 2 3
1 2 5
1 4 3
1 4 5
2 1 4
2 3 4
2 5 4
3 2 1
3 2 5
3 4 1
3 4 5
4 1 2
4 3 2
4 5 2
5 2 1
5 2 3
5 4 1
5 4 3
Kombinációk:
[_] [_] [_]
1 2 3
1 2 5
1 4 5
2 3 4
3 4 5
Kombinációkat generáló kód:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| #include <iostream>
#include <fstream>
using namespace std;
ofstream fout("output.txt");
void f(int szint, int n, int k, int megoldas[])
{
if (szint == k) {
// kiírás
for (int i = 0; i < k; i++)
fout << megoldas[i] << " ";
fout << endl;
}
else {
for (int i = 1; i <= n; i++) {
if (szint == 0
|| (i > megoldas[szint-1]
&& i%2 != megoldas[szint-1]%2))
{
megoldas[szint] = i;
f(szint+1, n, k, megoldas);
}
}
}
}
int main()
{
int n, k;
cout << "n = ";
cin >> n;
cout << "k = ";
cin >> k;
int megoldas[5];
// lexikografikus sorrendben
// állnak elő
f(0, n, k, megoldas);
return 0;
}
|
Variációkat generáló kód:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
| #include <iostream>
#include <fstream>
using namespace std;
ofstream fout("output.txt");
void f(int szint, int n, int k, int megoldas[])
{
if (szint == k) {
// kiírás
for (int i = 0; i < k; i++)
fout << megoldas[i] << " ";
fout << endl;
}
else {
for (int i = 1; i <= n; i++) {
bool volt = false;
for (int j = 0; j <= szint-1; j++)
if (megoldas[j] == i)
volt = true;
if (szint == 0
|| (!volt
&& i%2 != megoldas[szint-1]%2))
{
megoldas[szint] = i;
f(szint+1, n, k, megoldas);
}
}
}
}
int main()
{
int n, k;
cout << "n = ";
cin >> n;
cout << "k = ";
cin >> k;
int megoldas[5];
// lexikografikus sorrendben
// állnak elő
f(0, n, k, megoldas);
return 0;
}
|
2. Generáljuk az összes olyan számot az
{1,2,3,4} számjegyeket felhasználva, amelyben a számjegyek összege egyenlő k-val
(a felhasználó adja meg).
Ötlet:
1
2
3
4
5
6
7
| void f(int szint, int s, int megoldas[])
// ahol s a hátra levő összeg;
// ha s==0 akkor csak kiírunk;
// nem teszünk be s-nél nagyobb számjegyet:
// i <= 4 && i <= s
|
Példa:
k = 5-re (lexikografikus sorrendben):
11111
1112
1121
113
1211
122
131
14
2111
212
221
23
311
32
41
k = 5-re (növekvő sorrendben):
14
23
32
41
113
122
131
212
221
311
1112
1121
1211
2111
11111