Tài liệu bồi dưỡng học sinh giỏi THPT – Môn Tin học Phần II: Chuyên đề nâng caoCHUYÊN ĐỀ NÂNG CAO 6 CHUYÊN ĐỀ 6: QUY HOẠCH ĐỘNG D.. BÀI TOÁN XÂU PALINDROME XÂU ĐỐI XỨNG Palindrome hay cò
Trang 1Tài liệu bồi dưỡng học sinh giỏi THPT – Môn Tin học Phần II: Chuyên đề nâng cao
CHUYÊN ĐỀ NÂNG CAO 6
CHUYÊN ĐỀ 6: QUY HOẠCH ĐỘNG
D BÀI TOÁN XÂU PALINDROME (XÂU ĐỐI XỨNG)
Palindrome hay còn gọi là xâu đối xứng, xâu đối gương là tên gọi của những xâu kí tự mà khi viết
từ phải qua trái hay từ trái qua phải thì xâu đó không thay đổi
VD: MADAM, IOI, Nhờ tính chất đặc biệt đó mà có khá nhiều bài tập có liên quan đến Palindrome, phần lớn trong chúng thường đi kèm với QHĐ
Bài 1: Xem một xâu có phải là Palindrome hay không?
Đây là một bài cơ bản, nhưng quan trọng vì nó được đề cập đến trong nhiều bài tập khác Cách làm tốt nhất là duyệt đơn thuần mất O(N)
Ý tưởng: Chương trình con kiểm tra đối xứng
IsPalin(S):boolean;
• n = length(s)
• Duyệt từ 1 đến n div 2: Nếu S[i]<>S[n-i+1] thì Exit(False);
• Exit(True);
Giải thích:
- Ta kiểm tra từ đầu đến ½ xâu S: Nếu gặp cặp kí tự nào khác nhau tức là xâu S ko đối xứng: Khi
đó ta kết thúc chương trình và cho kết quả là False
- Còn nếu sau khi duyệt mà ko dừng tức là đối xứng: kết thúc và cho kết quả True
Bài 2: Palindrome liên tiếp dài nhất
Cho một xâu S <= 1000 kí tự; tìm palindrome dài nhất là xâu con của S (Xâu con là một dãy các kí tự liên tiếp)
Cách 1: Duyệt trâu: ta sẽ kiểm tra từng đoạn con của xâu S
Ý tưởng: Ta sẽ dùng vòng lặp để tìm đoạn Palin dài nhất
- Smax = ‘’
- Kiểm tra tất cả các xâu con: Nếu xâu nào là palin thì so sánh mới smax và lưu lại.
Code:
For i:=1 to n-1 do
For j:=i+1 to n do nếu Ispalin(sij) và sij dài hơn Smax thì smax=sij
Độ phức tạp: 2 vòng for là O(n 2 ) thêm ispalin là O(n) vậy độ phức tạp là O(n 3 ).
Với cách 1 này: Khi s khoảng 1000 kí tự thì thời gian chạy chương trình sẽ rất lớn, không đáp ứng được yêu cầu
Cách 2: QHĐ
Dùng mảng L[i, j] có ý nghĩa: L[i, j] = true nếu đoạn gồm các kí tự từ i đến j của S là palindrome
Ta có công thức là:
L[i, i] = True
L[i, j] = L[i+1, j-1]; ( nếu s[i] = s[j] )
L[i, j] = False; ( nếu s[i] <> s[j] )
Đoạn chương trình như sau:
for i:=1 to n do L[i,i]:=true;
for j:=2 to n do
for i:=1 to j-1 do
if s[i]<>s[j] then L[i,j]:= false
else L[i,j]:=(i+1=j) or L[i+1,j-1];
Kết quả là : Max(j-i+1) <=j thỏa F[i,j] = True
• Độ phức tạp thuật toán là 0(N^2)
Thuật toán tốt hơn cho bài này: Các em có thể tìm đọc thêm thuật toán manacher.
Trang 2Tài liệu bồi dưỡng học sinh giỏi THPT – Môn Tin học Phần II: Chuyên đề nâng cao Bài trên còn có một cách NlogN nữa là dùng Suffix Aray, thậm chí có cách O(N) là sử dụng Suffix Tree và thuật toán tìm LCA Đương nhiên cách cài đặt không hề dễ dàng
Bài 3: Chia Xâu thành các đoạn palindrome
Chia một xâu thành ít nhất các Palindrome (độ dài <=1000) Bài này phức tạp hơn bài trên, cách
làm thì vẫn là QHĐ
Gọi F[i] là số palindrome ít nhất mà đoạn 1 j chia thành được
Ta có công thức:
F[i] = max( F[j] + 1; "j < i thỏa mãn: đoạn j+1 i là palindrome)
Kết quả là F[n]
Đoạn chương trình như sau:
for i:=1 to n do f[i]:=n;
for i:=1 to n do
for j:=i-1 downto 0 do
if L[j+1,i] then F[i]:=min(f[i],f[j]+1);
Hai vòng for lồng nhau mất O(N^2)
Mảng L[i, j] có ý nghĩa tương tự bài 2
Bài 4: Pal - Ioicamp – Có bao nhiêu xâu con là Palindrome
Cho một xâu, hỏi nó có bao nhiêu xâu con là palindrome; xâu con ở đây gồm các kí tự không cần liên tiếp ( độ dài <= 120 )
Pal.iinp Pal.out
Đây là một bài tập rất thú vị Phương pháp là dùng QHĐ
Gọi F[i, j] là số palindrome là xâu con của đoạn i j
Ta có công thức :
• F[i, i] = 1;
• Nếu s[i] = s[j] thì f[i,j]=f[i+1,j]+f[i,j-1]+1
• Nếu s[i] <> s[j] thì f[i,j]=f[i+1,j]+f[i,j-1]-f[i+1,j-1];
Đoạn chương trình như sau :
//QHD: f[i,j] la so luong palindrome trong doan i j
for i:=1 to n do f[i,i]:=1;
for j:=2 to n do
for i:=j-1 downto 1 do
if s[i]=s[j] then f[i,j]:=f[i+1,j]+f[i,j-1]+1
else f[i,j]:=f[i,j-1]+f[i+1,j]-f[i+1,j-1];
write(f[1,n]);
Độ phức tạp của thuật toán là O(N2) Vì vậy, chúng ta hoàn toàn có thể làm với N = 1000
Bài 5: Thêm vào ít kí tự nhất để thành xâu Palindrome
Cho một xâu, hỏi phải thêm vào nó ít nhất bao nhiêu xâu kí tự để nó trở thành một palindrome (độ dài
<= 500)
Bài này cũng sử dụng QHĐ:
Gọi F[i, j] là số phép biến đổi ít nhất cần thêm vào đoạn i j để đoạn i j trở thành palindrome
Ta có công thức :
- F[i, i] = 0;
- Nếu s[i] = s[j] thì F[i, j] = F[i+1, j-1]
- Nếu s[i] <> s[j] thì F[i, j] = Min( F[i, j-1], F[i+1, j] ) + 1; Đoạn chương trình:
for i:=1 to n do f[i,i]:=0;
Trang 3Tài liệu bồi dưỡng học sinh giỏi THPT – Môn Tin học Phần II: Chuyên đề nâng cao for j:=2 to n do
for i:=j-1 downto 1 do
if s[i]<>s[j] then f[i,j]:=min(f[i,j-1],f[i+1,j])+1
else f[i,j]:=f[i+1,j-1];
write(f[1,n]);
Bài 6: The next palindrome - SPOJ
Cho nhiều số <= 106, với mỗi số, tìm số bé nhất có dạng palindrome lớn hơn số đã cho
Ví Dụ :
NextPalin.inp NextPalin.out 2
808 2133
818 2222 [i]Gợi ý: dùng phương pháp đếm kết hợp QHĐ