🎯 Mục tiêu bài học

  • Hiểu backtracking là gì: ta xây dựng lời giải dần dần theo từng bước.
  • Biết sinh ra tất cả các hoán vị (permutation) 1..n.
  • Biết sinh ra tổ hợp (combination) k phần tử từ n phần tử.

📘 Tư duy quay lui cơ bản

Ta xây dựng lời giải dần dần. Mỗi bước:

  1. Thử chọn một giá trị hợp lệ tiếp theo.
  2. Đệ quy sang bước tiếp theo.
  3. Quay lui (bỏ lựa chọn đó đi) để thử lựa chọn khác.

Ý tưởng này lặp đi lặp lại trong TỔNG HỢP, THỬ NGHIỆM, và GIẢI ĐỀ THI HSG.


💻 Ví dụ 1: sinh hoán vị 1..n

C++

#include 
using namespace std;

int n;
vector cur;
vector used;

void backtrack() {
    if ((int)cur.size() == n) {
        for (int x : cur) cout << x << " ";
        cout << "
"; return; } for (int val = 1; val <= n; val++) { if (!used[val]) { used[val] = 1; cur.push_back(val); backtrack(); cur.pop_back(); used[val] = 0; } } } int main() { cin >> n; used.assign(n+1, 0); backtrack(); }

Python

n = int(input())
cur = []
used = [False]*(n+1)

def backtrack():
    if len(cur) == n:
        print(*cur)
        return
    for val in range(1, n+1):
        if not used[val]:
            used[val] = True
            cur.append(val)
            backtrack()
            cur.pop()
            used[val] = False

backtrack()

💻 Ví dụ 2: sinh tổ hợp C(n, k)

Chỉ chọn đúng k phần tử tăng dần, không lặp lại.

Python (tổ hợp)

n, k = map(int, input().split())
cur = []

def backtrack(start):
    if len(cur) == k:
        print(*cur)
        return
    for val in range(start, n+1):
        cur.append(val)
        backtrack(val+1)
        cur.pop()

backtrack(1)

🧩 Bài tập luyện tập

  1. In tất cả các hoán vị của [1..n] theo thứ tự từ điển.
  2. In tất cả tổ hợp k phần tử từ [1..n].
  3. In tất cả chuỗi nhị phân độ dài n (gồm 0 và 1).
💡 Xem lời giải mẫu cho chuỗi nhị phân
n = int(input())
cur = []
def backtrack():
    if len(cur) == n:
        print("".join(cur))
        return
    for bit in ["0","1"]:
        cur.append(bit)
        backtrack()
        cur.pop()
backtrack()