(Bài 4 – Tuyển sinh 2007 - 2008)
Trên mặt phẳng tọa độ cho N hình chữ nhật với các cạnh song song với hệ trục tọa độ, các hình chữ nhật được đánh số từ 1 tới N. Hình chữ nhật thứ i được cho bởi 4 số nguyên dương xi1, yi1, xi2, yi2, trong đó (xi1, yi1) là tọa độ đỉnh trái dưới, còn (xi2, yi2)
là tọa độ đỉnh phải trên. Ta nói rằng hình chữ nhật thứ I nằm trong hình chữ nhật thứ j nếu trên mặt phẳng tọa độ, mọi điểm của hình chữ nhật i đều thuộc hình chữ nhật j.
Yêu cầu: Với N hình chữ nhật cho trước, hãy tìm K hình chữ nhật với chỉ số i1, i2, …, iK sao cho hình i1 nằm trong hình i2, hình i2 nằm trong hình i3, …, hình iK-1 nằm trong hình iK và K là lớn nhất. Biết rằng hai hình chữ nhật bất kì trong N hình chữ nhật đã cho hoặc rời nhau hoặc một trong hai hình nằm trong hình còn lại.
Dữ liệu: Vào từ file văn bản HCN.INP:
• Dòng đầu tiên chứa số nguyên dương N (1≤N≤100).
• N dòng tiếp theo, dòng thứ i chứa 4 số nguyên dương xi1, yi1, xi2, yi2.
Kết quả: Ghi ra file văn bản HCN.OUT số K tìm được.
Ví dụ:
HCN.INP HCN.OUT
3
1 1 7 4
3 1 6 62 2 5 4 2 2 5 4
Lời giải:
Bước 1, ta sắp xếp các hình chữ nhật theo thứ tự giảm dần của diện tích. Điều này đảm bảo một hình chữ nhật chỉ có thể bị bao bởi một hình chữ nhật xuất hiện phía trước nó. Đoạn chương trình sau thực hiện việc sắp xếp:
for i:=1 to n-1 do for j:=i+1 to n do if (dientich(h[i])<dientich(h[j])) then begin tam:=h[i];h[i]:=h[j];h[j]:=tam; end;
Giả sử các hình chữ nhật đã được sắp xếp là h1, h2, ..., hn. Ta gọi f[i] là độ dài lớn nhất của chuỗi hình chữ nhật lồng nhau kết thúc tại hình hi. Để tính f[i], ta tìm vị trí j lớn nhất sao cho j < i là hình chữ nhật hj bao hình chữ nhật hi, khi đó f[i]=f[j]+1. Nếu không tồn tại vị trí j thì hình chữ nhật hi không bị bao bởi hình chữ nhật nào và f[i]=1: f[i]:=1; {khởi tạo giá trị ban đầu cho f[i]}
for j:=i-1 downto 1 do
if bao(h[j],h[i]) then {j là vị trí lớn nhất mà hình chữ nhật h[j] bao hình chữ nhật h[i]}
begin
f[i]:=f[j]+1; {tính f[i] theo f[j]} break; {thoát khỏi vòng lặp} end;
if (f[i]>kq) then kq:=f[i]; {cập nhật lại kết qủa}
Chương trình:
const
finp='hcn.inp'; fout='hcn.out'; MAXN=105;
type hcn=record x1,y1,x2,y2: longint; end; var h: array[1..MAXN] of hcn; f: array[1..MAXN] of longint; i,j,n,kq: longint; tam:hcn; function dientich(a:hcn):longint; begin with a do dientich:=(x2-x1)*(y2-y1); end; function bao(a,b:hcn):boolean; begin
bao:=(a.x1<=b.x1) and (b.x2<=a.x2) and (a.y1<=b.y1) and (b.y2<=a.y2); end; begin assign(input,finp); reset(input); assign(output,fout); rewrite(output); readln(n); for i:=1 to n do with h[i] do readln(x1,y1,x2,y2); for i:=1 to n-1 do for j:=i+1 to n do if (dientich(h[i])<dientich(h[j])) then begin tam:=h[i];h[i]:=h[j];h[j]:=tam; end; kq:=0; for i:=1 to n do begin f[i]:=1;
for j:=i-1 downto 1 do if bao(h[j],h[i]) then begin
f[i]:=f[j]+1; break; end;
if (f[i]>kq) then kq:=f[i]; end; writeln(kq); close(input); close(output); end. Năm học 2008-2009 Bài 1: Mã hoá
Để quản lý tốt các hồ sơ trong kỳ thi tuyển sinh, hội đồng tuyển sinh trường PTNK đã quyết định đánh số các hồ sơ theo một phương pháp khoa học. Mã hồ sơ của thí sinh là một chuỗi gồm 10 chữ số. Tuy nhiên không phải bất kỳ chuỗi 10 chữ số nào cũng là mã hồ sơ hợp lệ bởi vì hội đồng tuyển sinh đưa ra một quy định ràng buộc chặt chẽ cho các chữ số đó. Nếu M=a1a2..a10 là một mã hồ sơ thì M phải thỏa mãn ràng buộc:
Nhờ quy định này, trong những trường hợp do sơ xuất có một chữ số trong mã hồ sơ bị mờ, không đọc được thì ta vẫn có thể xác định được giá trị của nó. Ví dụ như: (quy ước ? là chữ số bị mờ):
• Với M=00000000?1 thì có thể suy ra chữ số bị mờ là 5 vì theo ràng buộc, để S(M) là một số chia hết cho 11 nó chỉ có thể có giá trị là 55.
• Tương tự với M=00000001?1 thì có thể suy ra chữ số bị mờ là 9. • Tương tự với M=00722?0858 thì có thể suy ra chữ số bị mờ là 6.
Yêu cầu: Hãy viết chương trình giúp hội đồng tuyển sinh suy ra được chữ số bị mờ trong mã hồ sơ.
Dữ liệu: Vào từ file văn bản ENCODE.INP có chứa mã hồ sơ có 1 chữ số bị mờ được thay bằng dấu chấm hỏi.
Kết quả: Ghi ra file văn bản ENCODE.OUT chứa giá trị của chữ số bị mờ trong mã hồ sơ đã cho. Ví dụ: ENCODE.INP 00000000?1 ENCODE.OUT 5 00000001?1 9 00722?0858 6 Lời giải:
Ta thử thay từng chữ số từ 0 đến 9 vào vị trí "?" và tính xem điều kiện S(M) chia hết cho 11 có được thoả mãn hay không như đoạn chương trình sau đây:
for i:=1 to 10 do
{r là tổng các số hạng của S(M) trừ vị trí có dấu ‘?’} if (s[i]<>'?') then r:=(r+i*(ord(s[i])-ord('0'))) mod 11; i:=pos('?',s); {i là vị trí của dấu ‘?’}
for d:=0 to 9 do {duyệt qua tất cả các chữ số từ 0 đến 9} if (r+i*d) mod 11 = 0 then {kiểm tra xem S(M) có chia hết cho 11} begin
writeln(d); {d chính là chữ số cần tìm} break; {thoát khỏi vòng lặp} end; Chương trình: const finp='encode.inp'; fout='encode.out'; var s: string; i, r, d: longint; c: char;
begin assign(input,finp); reset(input); assign(output,fout); rewrite(output); readln(s); for i:=1 to 10 do
if (s[i]<>'?') then r:=(r+i*(ord(s[i])-ord('0'))) mod 11; i:=pos('?',s);
for d:=0 to 9 do
if (r+i*d) mod 11 = 0 then begin writeln(d); break; end; close(input); close(output); end.
Bài 2: Biến đổi dãy số
Cho dãy các số nguyên khác nhau đôi một a gồm n số a1, a2, ..., an và dãy số nguyên b gồm n số b1, b2, ..., bn. Trên dãy số a ta có thể áp dụng phép biến đổi T(i) thực hiện phép hoán vị giá trị hai phần tử ai và ai+1 (0<i<n) .Vấn đề đặt ra là có tồn tại hay không một dãy các phép biến đổi Ti1, Ti2, …, Tik sao cho khi áp dụng, dãy a ban đầu sẽ biến thành dãy b.
Ví dụ nếu dãy a là 1, 3, 2, 4 và dãy b là 2, 1, 3, 4 thì ta có thẻ sử dụng dãy 2 phép biến đổi T(2) và T(1) để biến đổi a thành b.
Yêu cầu: Cho hai dãy số a, b . Hãy chỉ ra một dãy các phép biến đổi a thành b hoặc cho biết không tồn tại dãy biến đổi như vậy.
Dữ liệu: Vào từ file văn bản EXARRAY.INP gồm 3 dòng:
• Dòng đầu tiên chứa số nguyên n là số lượng phần tử của mỗi dãy số (n<=100).
• Dòng thứ hai chứa n số nguyên đôi một khác nhau ứng với các phần tử của dãy số a.
• Dòng cuối cùng chứa n số nguyên ứng với các phần tử của dãy số b. Các số trong 2 mảng a và b đều có giá trị nằm trong đoạn [-10000,10000].
Kết quả: ghi ra file văn bản EXARRAY.OUT
• Nếu không thể biến đổi a thành b, file chứa số duy nhất số -1. • Trong trường hợp ngựoc lại, file sẽ gồm 2 dòng:
o Dòng đầu tiên chứa số nguyên k là số lượng phép biến đổi cần áp dụng.
o Dòng thứ hai chứa k số nguyên duơng i1, i2, …, ik ứng với các phép biến đổi Ti1, Ti2, …, Tik tìm được.
Hai số liên tiếp trên cùng một dòng được ghi cách nhau bởi một dấu cách.
EXARRAY.INP 4 1 3 2 4 2 1 3 4 EXARRAY.OUT 2 2 1 EXARRAY.INP 1 5 2 EXARRAY.OUT -1 Lời giải:
Thuật toán của ta đơn giản như sau: tìm b[1] trong dãy a rồi di chuyển lên đầu dãy a, sau đó lại tìm b[2] rồi di chuyển lên vị trí thứ hai của dãy a, ... Nếu tại một bước ta không tìm thấy số tương ứng trong dãy a thì in ra -1.
Đoạn chương trình sau thể hiện thuật toán:
for i:=1 to n do {duyệt qua tất cả các phần tử của dãy b} begin
vt[i]:=0; {vt[i] là vị trí xuất hiện của b[i] trong dãy a}
for j:=i to n do {duyệt qua các phần tử của dãy a để tìm số b[i]} if (a[j]=b[i]) then {tìm đặt b[i]}
begin
vt[i]:=j; {cập nhật lại vt[i]} break; {thoát khỏi vòng lặp} end;
if (vt[i]<>0) then {nếu tìm được số b[i]} begin
kq:=kq+vt[i]-i; {cần thực hiện thêm vt[i]-i phép biển đổi để đưa số từ vị trí vt[i] về vị trí i} for j:=vt[i]-1 downto i do trao(j) {thực hiện biến đổi!} end
else
begin {nếu không tìm được số b[i]} writeln(-1); {in ra -1}
exit; {thoát khỏi thủ tục} end;
end;
const MAXN=102; finp='exarray.inp'; fout='exarray.out'; var n: longint; a,b:array[1..MAXN] of longint; procedure nhap; var i: longint; begin readln(n);
for i:=1 to n do read(a[i]); for i:=1 to n do read(b[i]); end;
var kq: longint;
vt: array[1..MAXN] of longint; procedure trao(i: longint);
var tam: longint; begin
tam:=a[i]; a[i]:=a[i+1]; a[i+1]:=tam; end;
procedure xuly;
var i, j, tam: longint; begin for i:=1 to n do begin vt[i]:=0; for j:=i to n do if (a[j]=b[i]) then begin vt[i]:=j; break; end; if (vt[i]<>0) then begin kq:=kq+vt[i]-i;
for j:=vt[i]-1 downto i do trao(j) end else begin writeln(-1); exit; end; end; writeln(kq); for i:=1 to n do
write(j,' '); end; begin assign(input,finp); reset(input); assign(output,fout); rewrite(output); nhap; xuly; close(input); close(output); end.
Bài 3: Biến đổi bảng
Xét bảng vuông gồm n dòng và n cột. Các dòng được đánh số từ 1 đến n từ trên xuống dưới. Các cột được đánh số từ 1 đến n từ trái sang phải. Ô nằm ở vị trí dòng i và cột j của bảng được gọi là ô (i,j). Trên bảng A đã cho, khoảng cách từ ô (i,j) đến ô (p,q) được tính bằng |i-p|+|j-q|. Tại ô (i,j) của bảng A ghi số nguyên không âm aij, i=1,2,…,n; j=1,2,..,n. Dựa vào các số được ghi trên bảng A, người ta cần xây dựng một bảng B cùng kích thước với A mà trên đó ô (i,j) của bảng B sẽ được ghi số bij xác định như sau:
• Nếu aij > 0 thì bij = aij
• Nếu aij = 0 thì bij có giá trị bằng giá trị apq của ô (p,q) gần ô (i,j) nhất trong số các ô có giá trị khác không trên dòng i và cột j của bảng A. Trong truờng hợp có nhiều ô khác không có cùng khoảng cách nhỏ nhất đến (i,j) thì ô (p,q) đựoc chọn là ô chứa số lớn nhất trong chúng. Nếu tất cả các phần tử của dòng i và cột j đều có giá trị 0 thì bij = 0.
Yêu cầu: cho bảng A, hãy tìm bảng B.
Dữ liệu: vào từ file văn bản NZTABLE.INP gồm: • Dòng đầu tiên ghi số nguyên dương n (n ≤ 50)
• Dòng thứ i trong số n dòng tiếp theo ghi n số nguyên không âm ai1, ai2, …, ain là các số trên dòng thứ i của bảng, i=1,2,…,n; aij≤ 10000.
Kết quả: đưa ra file văn bản NZTABLE.OUT gồm n dòng, dòng thứ i ghi n số nguyên dương bi1, bi2, …, bin là các số trên dòng thứ i của bảng B.
Hai số liên tiếp trên cùng một dòng được ghi cách nhau bởi một dấu cách.
Ví dụ: NZTABLE.INP 4 1 0 3 0 4 0 0 5 0 0 6 0 0 0 0 0
NZTABLE.OUT 1 3 3 5 4 4 6 5 4 6 6 6 4 0 6 5 Lời giải:
Ta xây dựng mảng b giống như định nghĩa của đề bài như đoạn chương trình sau: if (a[i,j]>0) then b:=a[i,j] else {biển b chỉ phần tử bij. Nếu aij > 0 thì bij = aij}