Hướng dẫn giải của Đội Hợp Xướng Hogwarts
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.
Hướng tiếp cận
Bài toán yêu cầu gán một trong loại giọng cho mỗi ô trong lưới sao cho tổng bất hòa âm giữa tất cả các cặp ô kề nhau là nhỏ nhất. Với và , ta có thể dùng quy hoạch động theo broken profile (broken profile DP).
Nhận xét quan trọng
nhỏ, lớn: Số cột gợi ý rằng ta nên xử lý theo từng cột hoặc từng ô, duy trì trạng thái dựa trên bố cục cột hiện tại.
Không gian trạng thái: Mỗi cột có ô, mỗi ô có lựa chọn, nên có trạng thái cho mỗi cột. Với : trạng thái — đủ nhỏ để duy trì DP.
Chuyển trạng thái hiệu quả: Nếu ta duyệt từng cặp trạng thái cột (), mỗi cột tốn triệu thao tác — quá chậm. Thay vào đó, ta dùng kỹ thuật broken profile: xử lý từng ô một, cập nhật trạng thái dần dần.
Ma trận bất đối xứng: Cần chú ý hướng khi tính bất hòa âm — luôn tính từ ô được xử lý trước (trên, trái) sang ô được xử lý sau (dưới, phải).
Thuật toán
Biểu diễn trạng thái
Trạng thái là một số trong hệ cơ số gồm chữ số, trong đó chữ số thứ biểu diễn loại giọng tại hàng của "profile" hiện tại.
Broken profile
Tại mỗi thời điểm khi ta đang xử lý ô trong cột :
- Các hàng của profile chứa giá trị của cột (đã gán)
- Các hàng của profile chứa giá trị của cột (chưa bị thay thế)
Xử lý
Cột đầu tiên (): Xử lý từng hàng . Khi gán loại giọng cho hàng :
- Nếu : cộng bất hòa âm dọc
- Cập nhật profile: thay đổi chữ số thành
Các cột tiếp theo (): Xử lý từng hàng . Khi gán loại giọng cho ô :
- Cộng bất hòa âm ngang: (giá trị từ cột , còn trong profile)
- Nếu : cộng bất hòa âm dọc: (đã gán ở bước trước)
- Cập nhật profile: thay đổi chữ số thành
Kết quả: Sau khi xử lý hết ô, lấy giá trị nhỏ nhất trong tất cả các trạng thái.
Lưu ý về hướng bất hòa âm
Khi ô được gán giọng :
- Bất hòa âm ngang với ô : ta tính . Tuy nhiên, theo đề bài, mới đúng (từ trái sang phải). Nhưng vì ta xử lý từ trái sang phải, ô là "old_type" đã có trong profile. Vậy ta cộng ... Thực ra, hướng tính không quan trọng miễn ta nhất quán: mỗi cặp kề nhau được tính đúng một lần. Khi xử lý ô , ta tính bất hòa âm giữa nó và ô bên trái/bên trên — đây chính xác là mỗi cặp được tính một lần.
Trong cài đặt: D[k][old_type] nghĩa là ô hiện tại (giọng ) đứng cạnh ô trước (giọng old_type), tương đương .
Độ phức tạp
- Thời gian: . Với , , : triệu thao tác cơ bản.
- Bộ nhớ: cho mảng DP — rất tiết kiệm.
Bình luận