Tài liệu đưa ra một số thuật toán cơ bản được viết code minh họa bằng python 3, có thể sử dụng làm tài liệu tham khảo cho học sinh hoặc bồi dưỡng học sinh giỏi ở giai đoạn cơ bản.Tài liệu có thể dùng cho các lớp học theo định hướng CS ở chương trình phổ thông mới
Trang 1CHUYÊN ĐỀ 9: QUY HOẠCH ĐỘNG 9.1 MỘT SỐ BÀI TOÁN BẮT ĐẦU
1 BÀI TOÁN FIBONACI
Dãy Fibonaci được định nghĩa như sau:
1 2
1 2
1 (n 3)
F F F
Em hãy tìm số Fibonaci thứ n
* Ý tưởng đầu tiên – Thuật toán 1: Đệ quy
Nhìn vào công thức trên ta thấy ngay bản chất đệ quy, việc tính Fn ta có thể viết ngay rất dễ dàng và ngắn gọn:
Ta sẽ nhận xét về cách làm này thông qua ví dụ sau:
Khi ta gọi: x:=Fb(10) thì việc tính fb(10) này sẽ tính như sau:
X:= fb(9) + fb(8)
X:= fb(7) + fb(8) + fb(6) + fb(7)
X:= fb(5) + fb(6) + fb(6) + fb(7) + fb(4) + fb(5) + fb(5) + fb(6)
…
Ta thấy ngay bước thứ 3: có rất nhiều lời gọi hàm trùng lặp nhau: f6 gọi 3 lần, f5 gọi 3 lần … chính điều này làm cho thời gian thực thi thuật toán này rất lớn Chính vì vậy thuật toán đệ quy này chỉ chạy được với dữ liệu nhỏ Với n>=44 thuật toán trên không khả thi
* Ý tưởng cải tiến – Thuật toán 2: Quy hoạch động
Để thuật toán của ta chạy nhanh hơn ta thấy cần cải tiến làm sao để mỗi fb(x) chỉ cần tính một lần
Để làm điều này ta gọi F[i] là số fibonaci thứ i (f là mảng một chiều)
Khi đó ta thấy việc tính mảng này rất nhanh chóng:
Trong thuật toán trên: Việc tính các số fibonaci được lưu lại, mỗi số tính 1 lần, tính từ nhỏ đến lớn, Số fibo sau được tính thông qua các số fibo nhỏ hơn đó cũng là một phần của tư tưởng quy hoạch động
(chú thích: có các thuật toán khác tốt hơn nữa để tính số fibonaci thứ n, tuy nhiên để làm quen với tư tưởng QHĐ thì ta tạm dừng ở thuật toán này)
2 BÀI TOÁN SẮP BÒ NGUỒN: NTU – TÊN BÀI: SABO
Anh nông dân Bo có một đàn bò gồm rất nhiều con cái và con đực Trong một hội chợ, anh muốn sắp một hàng bò gồm n con Tuy nhiên những con bò đực rất hung hăng nếu đứng gần nhau, anh phải sắp tối thiểu k con bò cái xen giữa hai con bò đực để chúng khỏi húc nhau
Bạn hãy giúp anh Bo đếm thử xem có bao nhiêu cách để sắp một hàng gồm n con bò mà hai con bò đực bất kỳ không húc nhau (anh Bo có rất nhiều bò nên không sợ thiếu bò cái hoặc bò đực)
Ví dụ với n = 4 và k= 1, ta có 8 cách xếp như sau (M: bò đực, F: bò cái):
FFFF, MFFF, FMFF, FFMF, FFFM, MFMF, MFFM, FMFM
Input
Trang 2- Gồm hai số nguyên n và k cách nhau một khoảng trắng ( 1 ≤ n, k ≤ 1.000)
Output
- Số cách xếp hàng thỏa mãn yêu cầu Do số lượng này có thể rất lớn nên chỉ cần in ra tối đa 6 chữ số cuối cùng (modulo 1.000.000)
Ví dụ
Sapbo.inp Sapbo.out Sapbo.inp Sapbo.out
* ý tưởng đầu tiên: đệ quy quay lui
Ta nhận thấy bài này có thể quy về: Có bao nhiêu dãy nhị phân có độ dài n sao cho các kí tự
1 cách nhau k kí tự 0
Ta sẽ duyệt quay lui tất cả cách sắp bò (sinh ra tất cả các dãy nhị phân có độ dài n thỏa mãn điều kiện) và ta đếm
Nhận xét: ở đây n<=1000 vậy cách liệt kê dãy nhị phân này không thể chạy được trong thời gian cho phép
* ý tưởng 2: Quy hoạch động
Ta gọi B[i] là số cách sắp i con bò thỏa mãn điều kiện của bài toán Kết quả bài toán là B[n] Vấn đề đặt ra ở bài này là ta chưa có công thức để tính b[i] (Không giống bài 1: đã có công thức tính F[i] = f[i-1] + f[i-2])
Vậy để tính được mảng B này ta cần phải suy luận để tìm ra công thức Trong những trường hợp như vậy, cách làm chính là lấy giấy, bút, liệt kê thử xem với một số giá trị cụ thể:
Ví dụ: Với n=8 k=2 ta sẽ liệt kê thử số cách sắp:
Số cách sắp 1 con B[1] = 2 0 1
Số cách sắp 2 con B[2] = 3 00 01 10 (11 không được vì 2 bò đực sát nhau)
Số cách sắp 3 con B[3] = 4 000 001 010 100
Số cách sắp 4 con B[4] = 6 0000 0001 0010 0100 1000 1001
Số cách sắp 5 con B[5] = 9 00000 00001 00010 00100 01000 01001 10000 10001 10010
Số cách sắp 6 con B[6] = 13 000000 000001 000010 000100 …
Số cách sắp 7 con B[7] = 19 0000000 0000001 0000010 …
Số cách sắp 8 con B[8] = 28 00000000 00000010 00000100 …
…
Chắc chắn b[i] sẽ được tính thông qua các b[ ] nhỏ hơn nên ta thử:
B[1] = 1 + 1
B[2] = 2 + 1
B[3] = 3 + 1
B[4] = b[3] + b[1] ( 6 = 4 + 2)
B[5] = b[4] + b[2] ( 9 = 6 + 3)
B[6] = b[5] + b[3]
…
B[i] = b[i-1] + b[i-k-1] Đây chính là thứ ta cần tìm
Sau khi thử như trên ta có thể thấy được quy luật như sau:
Với i=1 đến k+1: b[i] = i+1
Với i=k+2 đến n: b[i] = b[i-1] + b[i-k-1]
Công thức ta vừa tìm được ở trên chính công thức quy hoạch Chương trình áp dụng công thức trên như sau:
fi = open("sapbo.inp","r")
fo = open("sapbo.out","w")
s = fi.read()
n, k = [int(x) for x in s.split()]
mod = 1000000
f = [ 0 for i in range(10001)]
Trang 3f[1] = 2 for i in range(2, k+2): f[i] = i+1 for i in range(k+2,n+1): f[i] = (f[i-1]+f[i-k-1]) % mod print(f[n],file = fo,end='')
fo.close()
3 MỘT SỐ BÀI TẬP MỞ ĐẦU LÀM QUEN VỚI QHĐ:
BÀI 9.1 1 LÁT GẠCH VERSION 1
Nguồn: SPOJ – bài: LATGACH
Cho một hình chữ nhật kích thước 2xN (1<=N<=100) Hãy đếm số cách lát các viên gạch nhỏ kích thước 1×2 và 2×1 vào hình trên sao cho không có phần nào của các viên gạch nhỏ thừa ra ngoài, cũng không có vùng diện tích nào của hình chữ nhật không được lát
Input
Gồm nhiều test, dòng đầu ghi số lượng test T ( T<=100 )
T dòng sau mỗi dòng ghi một số N
Output
Ghi ra T dòng là số cách lát tương ứng
Ví dụ
Latgach1.inp Latgach1.out Latgach1.inp Latgach1.out
3
1
2
3
1
2
3
2
4
5
5
8
Gợi ý: F[i] là số cách lát gạch cho sân kích thức 2 x i
Công thức tính Fi Fi1Fi2
BÀI 9.1 2 TỔNG ĐOẠN
Cho một dãy số nguyên A gồm n phần tử (ai<=10.000, n<=105) Nam thắc mắc liệu tổng của một đoạn bất kỳ trong dãy số trên là bao nhiêu Bạn hãy giúp cho Nam tính nhé!
Input
Dòng đầu ghi số lượng phần tử của dãy số N
Dòng 2: ghi các phần tử của dãy số A
Dòng 3: ghi số lượng test T ( T<=105)
T dòng sau mỗi dòng ghi hai số a và b (nam muốn tính tổng của đoạn [a b]
Output Ghi ra T dòng tổng tương ứng của các bộ test
Ví dụ
Tongdoan.inp Tongdoan.out
3
1 3 5
2
1 2
1 3
4
9
Gợi ý: Nếu dùng cách duyệt bình thường O(n2) thì chắc chắn sẽ không chạy được với n10 ;5 t105 Gọi
1
i
k
; Khi đó tổng từ a đến b là FbFa1
BÀI 9.1 3 HIỆU LỚN NHẤT: NGUỒN: NTU – BÀI: HISO
Cho một dãy n số nguyên a1, a2, , an Hãy tìm hai chỉ số i, j sao cho i < j và hiệu aj - ai là lớn nhất
Trang 4Dữ liệu vào: gồm 2 dòng
- Dòng 1: là số nguyên n (2 ≤ n ≤ 105)
- Dòng 2: gồm n số nguyên a1, a2, , an (0 ≤ ai ≤ 109)
Dữ liệu xuất:
- Là giá trị lớn nhất của hiệu aj - ai
Ví dụ
hieuso.inp hieuso.out hieuso.inp hieuso.out
3
1 2 3
2 5 1 3
3
Cách 1: Duyệt với độ phức tạp O(n2), thực hiện được với n105
Cách 2: Sử dụng thuật toán quy hoạch động sau đây
Gọi F là giá trị nhỏ nhất trong đoạn từ 1 đến i i
Khi đó để tìm giá trị lớn nhất từ i đến j ta sẽ duyệt như sau:
for i in range(2,n+1):
res = max(res, a[i] - F[i])
Kết quả là Res
Chương trình:
fi = open("hieuso.inp","r")
fo = open("hieuso.out","w")
n = int(fi.readline())
a = [int(x) for x in fi.readline().split()]
F = [0 for i in range(100001)]
F[0] = a[0]
for i in range(1,n):
if F[i-1]<a[i]:
F[i] = F[i-1]
else:
F[i] = a[i]
res = 0 for i in range(1,n):
if res < a[i] - F[i]:
res = max(res, a[i] - F[i]) print(res,file = fo, end='')
fo.close() fi.close()
Cách 3:
Gọi minF là giá trị nhỏ nhất trong đoạn từ 1 đến i i
Gọi maxF là giá trị lớn nhất trong đoạn từ i đến n i
Khi đó ta có resmax(res, maxFimin )Fi
Chương trình
fi = open("hieuso.inp","r")
fo = open("hieuso.out","w")
n = int(fi.readline())
a = [int(x) for x in fi.readline().split()] minF = [0 for i in range(100001)]
maxF = [0 for i in range(100001)]
minF[0] = a[0]
for i in range(1,n):
minF[i] = min(a[i], minF[i-1]) maxF[n-1] = a[n-1]
Trang 5for i in range(n-1,0,-1):
maxF[i] = max(a[i], maxF[i+1]) res = 0
for i in range(n):
res = max(res, maxF[i] - minF[i]) print(res,file = fo, end='')
fo.close() fi.close()
4.4 LÁT GẠCH VERSION 2: NGUỒN NTU – BÀI: LAGA
Có một khoảng sân hình chữ nhật kích thước 2 x n ô vuông, gồm 2 hàng và n cột Đánh số hàng từ 1 đến 2 theo thứ tự từ trên xuống dưới, đánh số cột từ 1 đến n theo thứ tự từ trái qua phải Người ta muốn lát sân bằng gạch màu trắng và điểm xuyết một số ô gạch màu đen, mỗi ô vuông được lát bởi một viên gạch, sao cho không có hai viên gạch màu đen nào chung cạnh với nhau Hỏi có tất cả bao nhiêu cách khác nhau để lát khoảng sân trên (hai cách lát sân được gọi là khác nhau nếu tồn tại tối thiểu một ô ở dòng i cột j được lát gạch màu trắng ở cách này và lát gạch màu đen ở cách kia)
Ví dụ với n = 2, ta có 7 cách lát sân sau đây:
Input : Một số nguyên n (1 ≤ n ≤ 1000)
Output Số cách lát gạch khoảng sân theo yêu cầu trên Số lượng này có thể rất lớn nên chỉ cần in ra 8
số cuối (mod 100.000.000)
Ví dụ
Laga.inp Laga.out Laga.inp Laga.out Laga.inp Laga.out
Hướng dẫn
0 0
F ; 𝐹 = (𝐹 + 2 ∗ 𝐹 ) % 1 0
Kết quả: F Độ phức tạp: O(n) n
4.5 DẠO CHƠI BẰNG XE BUÝT
Nguồn: SPOJ – Bài: KMBUS
Một tuyến đường ở thành phố có các bến xe bus ở từng km tuyến đường Mỗi lần qua bến, xe đều đỗ để đón khách Mỗi bến đều có điểm xuất phát Một xe chỉ chạy không quá B km kể từ điểm xuất phát của nó Hành khách khi đi xe sẽ phải trả tiền cho độ dài đoạn đường mà họ ngồi trên xe Cước phí cần trả để đi đoạn đường độ dài i là Ci (i=1,2 B) Một du khách xuất phát từ 1 bến nào đó muốn đi dạo L (km) theo tuyến nói trên Hỏi ông ta phải lên xuống xe như thế nào để tổng số tiền phải trả là nhỏ nhất có thể
Dữ liệu vào
Dòng đầu ghi 2 số nguyên dương B, L
Dòng thứ i trong số B dòng tiếp theo ghi 1 số nguyên dương Ci ( 1 ≤ i ≤ B )
Kết qủa
Một dòng duy nhất là số tiền nhỏ nhất phải trả
Giới hạn
0 ≤ B ≤ 100 0 ≤ L ≤ 10000 0 ≤ Ci ≤ 100
Ví dụ
5 7
3
4
6
9
14
Trang 622 Công thức QHĐ: F[0] 0; [ ] min( [ ], [ ] F i F i F j C i j[ ]);i 1,2, ,n; j max(0,i B), ,i 1 Nếu tìm đường đi thì ta truy vết như sau:
I = L;
while i>0:
i = i-F[i];
print(i,end=' ');
9.2 QUY HOẠCH ĐỘNG VỚI MẢNG 2 CHIỀU
1 BÀI TOÁN: XÂU CON CHUNG DÀI NHẤT
Bài toán: Cho hai xâu X và Y Hãy tìm xâu con chung dài nhất (LCS) của hai xâu X và Y Xâu con chung là xâu khi xóa đi một số kí tự của hai xâu thì hai xâu còn lại của chúng giống nhau
Ví dụ: X = 'CEACEEC' Y = 'AECECA'
Xâu con chung: ECEC, AEEC Thuật toán:
Đặt các chuỗi đầu vào lần lượt là X[0 m-1] và Y[0 n-1] có độ dài m và n
Và đặt L(X[0 m-1], Y[0 n-1]) là độ dài LCS của hai dãy X và Y
Sau đây là định nghĩa đệ quy của 𝐿(𝑋[0 𝑚 − 1], 𝑌[0 𝑛 − 1])
Nếu các ký tự cuối cùng của cả hai chuỗi khớp nhau (hoặc X[m-1] == Y[n-1]) thì:
L(X[0 m-1], Y[0 n-1]) = 1 + L(X[0 m-2], Y[0 n-2])
Nếu các ký tự cuối cùng của cả hai chuỗi không khớp (hoặc X[m-1] != Y[n-1]) thì:
L(X[0 m-1], Y[0 n-1]) = max( L(X[0 m-2], Y[0 n-1]), L(X[0 m-1], Y[0 n-2]) )
Ví dụ:
1) Xem xét chuỗi đầu vào "AGGTAB" và "GXTXAYB" Các ký tự cuối cùng khớp với các
chuỗi Vì vậy độ dài của LCS có thể được viết là:
L("AGGTAB", "GXTXAYB") = 1 + L("AGGTA", "GXTXAY")
2) Xem xét các chuỗi đầu vào "ABCDGH" và "AEDFHR" Các ký tự cuối cùng không khớp với chuỗi Vậy độ dài của LCS có thể được viết là:
L("ABCDGH", "AEDFHR") = max( L("ABCDG", "AEDFHR"), L("ABCDGH", "AEDFH") ) Vậy bài toán LCS có thuộc tính cấu trúc con tối ưu vì vấn đề chính có thể được giải quyết bằng cách
sử dụng các giải pháp cho các vấn đề con
Từ đó ta có công thức Quy hoạch động như sau:
Khi áp dụng QHĐ để giải bài này ta chú ý xây dựng công thức như sau:
Trang 7Gọi 𝐿[𝑖][𝑗] là độ dài dãy con chung dài nhất của 2 dãy X[0 i-1] và b[0 j-1] Khi đó ta có:
Nếu 𝑖 = 0, 𝑗 = 0 thì 𝐿[𝑖][𝑗] = 0
Nếu 𝑎[𝑖 − 1] ! = 𝑏[𝑗 − 1] thì 𝐿[𝑖][𝑗] = 𝑀𝑎𝑥( 𝐿[𝑖 − 1][𝑗] , 𝐿[𝑖][𝑗 − 1])
Nếu 𝑎[𝑖 − 1] = 𝑏[𝑗 − 1] thì 𝐿[𝑖][𝑗] = 1 + 𝐿[𝑖 − 1][𝑗 − 1]
Kết quả của bài toán Độ dài xâu con chung dài nhất là 𝐿[𝑚][𝑛]
Đoạn code:
def LCS(a,b):
for i in range(m+1):
for j in range(n+1):
if i==0 or j==0:
F[i][j] = 0 elif a[i-1] == b[j-1]:
F[i][j] = F[i-1][j-1] + 1 else:
F[i][j] = max(F[i-1][j], F[i][j-1]) return F[m][n]
Để truy vết kết quả xâu con chung ta sẽ truy vết dựa vào mảng L: Đi từ ô L[m][n] về ô L[0][0]
def trace(a,b):
i= m
j = n res ='' while i>0 and j>0:
if a[i-1] ==b[j-1]:
res = a[i-1]+res
i -= 1
j -= 1 elif F[i][j] == F[i-1][j]:
i -= 1 else:
j -= 1 return res
BÀI TẬP ÁP DỤNG BÀI 9.2 1 XÂU CON CHUNG DÀI NHẤT (QBSTR)
Nguồn bài: http://vn.spoj.com/problems/QBSTR/
Xâu kí tự X được gọi là xâu con của xâu kí tự Y nếu ta có thể xoá đi một số kí tự trong xâu Y để được xâu X Cho biết hai xâu kí tự A và B, hãy tìm xâu kí tự C có độ dài lớn nhất và là con của cả A
và B
Dữ liệu vào:
+ Dòng thứ nhất chứa xâu A
+ Dòng thứ hai chứa xâu B
Dữ liệu ra:
+ Dòng 1: chứa số nguyên là độ dài lớn nhất của xâu con tìm được
+ Dòng 2: chứa xâu con chung dài nhất của hai xâu A và B
Ví dụ:
abc1def2ghi3 abcdefghi123
10 abcdefghi3 Cách 1: Giải bằng CT ở phần lí thuyết
Như vậy độ phức tạp bộ nhớ của bài toán là O(n2), độ phức tạp thời gian là O(n2)
Trang 8Có một phương pháp cài đặt tốt hơn, chỉ với độ phức tạp bộ nhớ O(n) dựa trên nhận xét sau: để tính
ô L[i][j] của bảng phương án, ta chỉ cần 3 ô L[i−1][j−1], L[i−1][j] và L[i][j−1]
Tức là để tính dòng L[i] thì chỉ cần dòng L[i−1] Do đó ta chỉ cần 2 mảng 1 chiều để lưu dòng vừa tính (P) và dòng đang tính (L) mà thôi Cách cài đặt mới như sau:
Cách 2:
Ta sử dụng 2 mảng một chiều P và L, trong đó P là mảng đã tính ở bước thứ i–1, L là mảng tính ở bước thứ i Ta có, tại bước i, ta xét kí tự x[i-1], với mỗi j = 1… n
Nếu x[i] = y[j] thì L[j] = P[j–1] + 1;
Nếu x[i] ≠ y[j] thì L[j] = max(P[j], L[j–1])
a = input()
b = input()
m = len(a)
n = len(b)
L = [0 for i in range(1001)]
def LCS(a,b):
P = [0 for i in range(1001)]
for i in range(m+1):
for j in range(n+1):
if j==0:
L[j] = 0 elif a[i-1] == b[j-1]:
L[j] = L[j-1] + 1 else:
L[j] = max(P[j], L[j-1])
P = L.copy() return L[n]
def trace(a,b):
i= m
j = n res ='' while i>0 and j>0:
if a[i-1] ==b[j-1]:
res = a[i-1]+res
i -= 1
j -= 1 elif L[j] == L[j-1]:
j -= 1 else:
i -= 1 return res print(LCS(a,b)) print(trace(a,b))
Bài tập tương tự:
Cho hai xâu x gồm m và y gồm n kí tự Cần xóa đi từ xâu x, dx kí tự và từ xâu y, dy kí tự để thu được hai xâu giống nhau Hãy xác định giá trị nhỏ nhất của tổng dx+dy
Thuật toán:
k = F[m,n];
dx = length(x) – k;
dy = length(y) – k;
max
dx dy
(Lưu ý: Đối với bài toán cho hai dãy số nguyên ta vẫn áp dụng thuật toán tương tự, thay vì xử lí các
kí tự, ta sẽ xử lí từng phần tử của mảng)
Trang 9BÀI 9.2 2 ĐOẠN CHUNG
Hãy tìm chiều dài lớn nhất k trong số các đoạn chung của hai xâu x và y
Thí dụ, x = "xabcxxabcdxd", y = "aybcyabcdydy" có chiều dài của đoạn chung dài nhất là 4 ứng với đoạn "abcd"
Input:
+ Dòng 1 chứa xâu x;
+ Dòng 2 chứa xâu y;
Output: nguyên k là độ dài đoạn chung tìm được
Ví dụ:
xabcxxabcdxd aybcyabcdydy
4
Thuật toán
Dùng mảng hai chiều L[i][j] là chiều dài lớn nhất của hai đoạn giống nhau 𝑥[𝑖 − 𝑘 𝑖 − 1] và 𝑦[𝑗𝑘 𝑗 − 1], sao cho k max Ta có,
Nếu 𝑥[𝑖 − 1] = 𝑦[𝑗 − 1] thì 𝐿[𝑖][𝑗] = 𝐿[𝑖– 1][𝑗– 1] + 1;
Nếu 𝑥[𝑖 − 1] ≠ 𝑦[𝑗 − 1] thì 𝐿[𝑖][𝑗] = 0
Chiều dài đoạn con chung dài nhất sẽ là Max{L[i][j] | 1 i len(x), 1 j len(y)}
Các bài tương tự
1 Đoạn chung 2 Cho xâu x gồm m kí tự và xâu y gồm n kí tự Tìm đoạn chung dài nhất của hai xâu này Kết quả cho ra 4 giá trị dx, cx, dy, cy, trong đó x[dx cx] = y[dy cy] là hai đoạn tìm được
Yêu cầu: Kết quả ghi ra file "DCHUNG.OUT" gồm một dòng chứa 4 số nguyên tương ứng với dx,
cx, dy, cy Mỗi số cách nhau ít nhất một dấu cách
Bài toán mở rộng: yêu cầu ghi ra các phần tử của đoạn chung
Ví dụ:
xabcxxabcdxd aybcyabcdydy
4 abcd Thuật toán bài đoạn chung 2:
Khi phát hiện a[j] > kmax ta ghi nhận imax = i; jmax = j; kmax = k Cuối thủ tục ta tính cx = imax;
dx = cx–kmax+1; cy = jmax; dy = cy–kmax+1
2 Đoạn chung 3 Cho hai dãy số nguyên a gồm m và b gồm n phần tử Xác định chiều dài lớn nhất k
để hai dãy cùng chứa k phần tử liên tiếp như nhau: a[i] = b[j], a[i+1] = b[j+1],…,a[i+k–1] = b[j+k–1]
(Lưu ý: Thuật toán xử lí trên mảng số nguyên, cách làm tương tự bài đoạn chung.)
BÀI 9.2 3 DÃY CON CHUNG DÀI NHẤT
(Nguồn bài: Câu 3,Quảng Bình 2012-2013)
Cho dãy số nguyên A gồm N phần tử a1, a2, , aN và dãy số nguyên B gồm M phần tử b1, b2, , bM Các phần tử trong một dãy số có giá trị khác nhau từng đôi một (1 ≤ ai, bj ≤ 2x109; 1 ≤ N ≤ 100; 1 ≤ i ≤ N; 1 ≤ M ≤ 100; 1 ≤ j ≤ M) Dãy C được gọi là dãy con của dãy A nếu dãy C nhận được từ dãy A bằng cách xóa đi một số phần tử và giữ nguyên thứ tự của các phần tử còn lại Nếu dãy C là dãy con của dãy
A và cũng là dãy con của dãy B thì dãy C được gọi là dãy con chung của hai dãy A và B
Yêu cầu: Hãy tìm dãy C là dãy con chung của hai dãy A và B sao cho số lượng phần tử của dãy C là lớn nhất
Dữ liệu vào:
- Dòng 1: Ghi số nguyên dương N là số lượng phần tử của dãy A
Trang 10- Dòng 2: Ghi N số nguyên là giá trị của các phần tử trong dãy A, các số được ghi cách nhau ít nhất một dấu cách
- Dòng 3: Ghi số nguyên dương M là số lượng phần tử của dãy B
- Dòng 4: Ghi M số nguyên là giá trị của các phần tử trong dãy B, các số được ghi cách nhau
ít nhất một dấu cách
Kết quả ra:
- Dòng 1: Ghi số nguyên dương K là số lượng phần tử của dãy C
- Dòng 2: Ghi K số nguyên là giá trị của các phần tử trong dãy C, các số được ghi cách nhau một dấu cách
- Dòng 3: Ghi K số nguyên dương lần lượt là chỉ số của các phần tử trong dãy A tương ứng với các giá trị của phần tử đó trong dãy C, các số được ghi cách nhau một dấu cách
- Dòng 4: Ghi K số nguyên dương lần lượt là chỉ số của các phần tử trong dãy B tương ứng với các giá trị của phần tử đó trong dãy C, các số được ghi cách nhau một dấu cách
Ví dụ:
6
9 3 1 12 6 15
5
3 12 7 6 15
4
3 12 6 15
2 4 5 6
1 2 4 5 BÀI 9.2 4 BLGEN - CHUỖI GEN ĐẶC TRƯNG
Tế bào của một cá thể sinh vật ngoài hành tinh mới được phát hiện gồm rất nhiều gen, mỗi gen trong chuỗi gen của tế bào đều có số lượng nào đó các nucleotide (ký hiệu là nu) Các chuyên gia thường quan tâm chuỗi gen của mỗi cá thể dưới góc độ một chuỗi số lượng tương ứng các nu gọi tắt là chuỗi nu), do đó chuỗi sẽ như là một dãy số nguyên dương đồng thời số số hạng của dãy này
sẽ được gọi là độ dài của chuỗi Mỗi gen được xem là đặc biệt nếu số nu của nó hoặc là bình phương của một số nguyên hoặc là lập phương của một số nguyên tố
Để nghiên cứu khả năng biến đổi gen của loài sinh vật nói trên, các nhà khoa học xem xét hai mẫu chuỗi nu của hai cá thể và quan tâm đến mức độ "giống nhau" giữa chúng theo cách tìm ra chuỗi con chỉ gồm các gen đặc biệt mà cùng xuất hiện ở cả hai chuỗi nu (mỗi chuỗi con như vậy đều được gọi là chuỗi đặc trưng chung của hai chuỗi nu) Lưu ý rằng, chuỗi con của một chuỗi nu X, là chuỗi thu được
từ X bằng cách giữ nguyên tất cả hoặc loại bỏ đi một số nào đó các gen mà vẫn giữ thứ tự xuất hiện trong chuỗi X
Yêu cầu: Xác định độ dài lớn nhất L của chuỗi đặc trưng chung của hai chuỗi nu cho trước
Dữ liệu:
Dòng đầu ghi lần lượt các số hạng của chuỗi nu thứ nhất
Dòng tiếp theo ghi lần lượt các số hạng của chuỗi nu thứ hai
Tất cả các số hạng của hai chuỗi đều nguyên dương và không vượt quá 1019
(Độ dài của mỗi chuỗi nu đều không vượt quá 1000)
Kết quả: Ghi ra file văn bản GEN.OUT duy nhất một số nguyên L tìm được
Ví dụ:
2 9 8 4 1 27 4 6
5 6 9 1 8 2 6 27 1 4
4
(Giải thích: L = 4, một trong các chuỗi đăc trưng chung là: 9, 1, 27, 4)
Ràng buộc: 60% số test ứng với 60% số điểm của bài ứng với tình huống độ dài của hai chuỗi
nu không vượt quá 255 và giá trị của mỗi số hạng đều không vượt quá 106