Professional Documents
Culture Documents
(tập 1)
1
Bài 1: Xếp khách
Một khách sạn có N phòng đôi (phòng cho 2 người) được đánh số từ 1 đến
N. Khi có một đoàn khách đến thuê phòng, tiếp tân của khách sạn sẽ xếp
khách vào phòng tho nguyên tắc sau: mỗi cặp khách sẽ được xếp vào phòng
có chỉ số nhỏ nhất trong số các phòng trống. Nếu số lượng khách của đoàn
là số lẻ thì người cuối cùng của đoàn khách sẽ được xếp vào phòng có chỉ
số nhỏ nhất trong số các phòng còn trống. Nếu không còn phòng trống thì
số khách chưa có phòng sẽ được xếp tuần tự từng người một vào phòng có
chỉ số nhỏ nhất trong số các phòng mới có một khách (của đoàn khách
trước đó). Đầu tiên các phòng của khách sạn đều trống.
- Yêu cầu: cho trước trình tự đến của các đoàn khách và số lượng
khách của mỗi đoàn. Hãy xác định số lượng khách trong mỗi phòng của
khách sạn.
- Dữ liệu vào: file văn bản ROOMS.INP
+ Dòng đầu tiên chứa 2 số nguyên dương N (1<=N<=100) và G
được ghi cách nhau bởi dấu cách. N là số phòng của khách sạn, G là số
lượng đoàn khách.
+ Dòng thứ i trong số G dòng tiếp theo chứa số lượng khách của
đoàn khách thứ i (các đoàn khách được đánh số theo số thứ tự đến khách
sạn, bắt đầu từ 1).
Giả thiết rằng, không có 2 đoàn khách nào đến khách sạn cùng thời
điểm và tổng số khách của tất cả các đoàn không vượt quá sức chứa của
khách sạn (<= 2N).
- Kết quả: file văn bản ROOMS.OUT gồm N dòng. Dòng thứ i
chứa số lượng khách của phòng thứ i (1 <= i <= N).
- Ví dụ:
ROOMS.INP ROOMS.OUT
7 3 2
3 1
1 1
4 2
2
0
0
- Gợi ý và lời giải:
* Khi còn phòng trống thì xếp theo số phòng tăng dần, mỗi phòng
xếp đủ 2 người, nếu còn lẻ người cuối cùng thì xếp người đó vào 1 phòng.
* Khi hết phòng trống thì theo số hiệu phòng tăng dần xếp thêm
vào các phòng mới có 1 người cho đủ 2 người.
2
Chương trình dùng mảng 1 chiều P[1..N] of 0..2 để ghi nhận số
khách xếp vào các phòng. P[i]=0 là phòng i còn trống, P[i]=1 là phòng i có
1 người, P[i]=2 là phòng i có 2 người. Đồng thời dùng biến t để theo dõi
phòng cuối cùng đã có người (1 hoặc 2 người), dựa vào đó để xếp tiếp
khách vào phòng t+1. Khi hết phòng trống thì dùng biến t1 theo dõi phòng
có 1 người có chỉ số bé nhất để xếp nốt khách (từng người một) vào các
phòng mới có 1 người.
• Chương trình 1:
PROGRAM XepKhach;
USES Crt;
Const
max=1001;
Fi='Rooms.inp';
Fo='Rooms.out';
Var
P:array[0..max] of 0..2;
n,g,t,t1,i,x:integer;
F:text;
{----------------------}
BEGIN
clrscr;
assign(F,Fi); reset(F);
readln(F,n,g);
t:=0;
FillChar(P,SizeOf(P),0);
for i:=1 to g do
begin
readln(F,x);
while (t<n) and (x>1) do
begin
inc(t);
P[t]:=2;
dec(x,2);
end;
if (x=1) and (t<n) then
begin
inc(t);
P[t]:=1;
dec(x);
end;
if (t=n) and (x>0) then
begin
t1:=0;
while (P[t1]<>1) and (t1<n) do
begin
inc(t1);
3
if (P[t1]=1) and (x>0) then
begin
P[t1]:=2;
dec(x);
end;
end;
end;
end;
Close(F);
assign(F,Fo); Rewrite(F);
for i:=1 to n do Writeln(F,P[i]);
Close(F);
END.
• Chương trình 2:
PROGRAM XepKhach;
USES Crt;
Const
max=100;
Fi='Rooms.inp';
Fo='Rooms.out';
Var
P,D:array[1..max] of integer;
n,g,tongkhach:integer;
loi:boolean;
F:text;
procedure Nhap;
var k:integer;
begin
assign(F,Fi); reset(F);
Readln(F,n,g);
for k:=1 to g do Readln(F,D[k]);
Close(F);
FillChar(P,SizeOf(P),0);
end;
procedure Xuat;
var k:integer;
begin
Assign(F,Fo); Rewrite(F);
if loi then write(F,'Khach san qua suc chua!')
else
for k:=1 to n do Writeln(F,P[k]);
Close(F);
end;
function DemPhongTrong:integer;
var k,l:integer;
begin
4
l:=0;
for k:=1 to n do if P[k]=0 then l:=l+1;
DemPhongTrong:=l;
end;
procedure XepKhach(x:integer);
var k,l:integer;
begin
l:=DemPhongTrong;
if x<=0 then exit else
if x=1 then
begin
if l>0 then
for k:=1 to n do if P[k]=0 then begin P[k]:=x; break;
end;
if l=0 then
for k:=1 to n do if P[k]=1 then begin P[k]:=P[k]+x;
break; end;
end
else
begin
if l>0 then
for k:=1 to n do if P[k]=0 then begin P[k]:=2;
XepKhach(x-2); break; end;
if l=0 then
for k:=1 to n do if P[k]=1 then begin
P[k]:=P[k]+1;XepKhach(x-1); break; end;
end;
end;
procedure XuLy;
var k:integer;
begin
tongkhach:=0;
for k:=1 to g do tongkhach:=tongkhach+D[k];
if tongkhach<=n*2 then
begin
for k:=1 to g do XepKhach(D[k]);
loi:=false;
end
else
loi:=true;
end;
BEGIN
clrscr;
Nhap;
XuLy;
Xuat;
5
END.
8
while (s<>'') and (s[length(s)]=' ') do
delete(s,length(s),1);
ch:=s[1];
delete(s,1,2);
p:=pos(' ',s);
if ch='H' then
begin
s1:=copy(s,1,p-1);
val(s1,i,code);
delete(s,1,p);
val(s,j,code);
H[i,j]:=1;
if H[i,j+1]=0 then H[i,j+1]:=2;
end
else
if ch='V' then
begin
s1:=copy(s,1,p-1);
val(s1,j,code);
delete(s,1,p);
val(s,i,code);
V[i,j]:=1;
if V[i+1,j]=0 then V[i+1,j]:=2;
end;
end;
end;
{----------------------}
Function ngang(i,j:integer):integer;
var l:integer;
begin
l:=1;
while (H[i,j]=1) and (j<n) do
begin
inc(l);
inc(j);
end;
if (H[i,j]=1) and (j=n) then inc(l);
ngang:=l;
end;
{-----------------}
procedure taoR;
var i,j,l,jj:integer;
begin
fillchar(R,SizeOf(R),0);
for i:=1 to n do
for j:=1 to n do
if (R[i,j]=0) and (H[i,j]=1) then
begin
l:=ngang(i,j)-1;
9
jj:=j;
R[i,jj]:=l;
while l>0 do
begin
dec(l);
inc(jj);
R[i,jj]:=l;
end;
end;
end;
{----------------------}
Function doc(i,j:integer):integer;
var l:integer;
begin
l:=1;
while (V[i,j]=1) and (i<n) do
begin
inc(l);
inc(i);
end;
if (V[i,j]=1) and (i=n) then inc(l);
doc:=l;
end;
{------------------}
procedure taoD;
var i,j,l,ii:integer;
begin
fillchar(D,SizeOf(D),0);
for i:=1 to n do
for j:=1 to n do
if (D[i,j]=0) and (V[i,j]=1) then
begin
l:=doc(i,j)-1;
ii:=i;
D[ii,j]:=l;
while l>0 do
begin
dec(l);
inc(ii);
D[ii,j]:=l;
end;
end;
end;
{----------------------}
function min(x,y:integer):integer;
begin
if x<y then min:=x else min:=y;
end;
{----------------------}
10
procedure dem;
var i,j,l,s:integer;
begin
fillchar(kq,SizeOf(kq),0);
for i:=1 to n do
for j:=1 to n do
if H[i,j]=1 then
begin
l:=min(R[i,j],D[i,j]);
for s:=1 to l do
if (D[i,j+s]>=s) and (R[i+s,j]>=s) then inc(kq[s]);
end;
end;
{------------------}
procedure Xuat;
var i,l: integer;
begin
assign(f,fo); Rewrite(f);
l:=0;
for i:=1 to max do
if kq[i]>0 then inc(l);
writeln(f,l);
for i:=1 to max do
if kq[i]>0 then writeln(f,kq[i],' ',i);
Close(f);
end;
{--------------------}
BEGIN
Nhap;
taoR;
taoD;
dem;
Xuat;
END.
Procedure Xuat;
var l:integer;
begin
assign(f,fo); Rewrite(f);
for l:=1 to N do write(f,A[l],' ');
Close(f);
end;
{------------------}
BEGIN
Nhap_XuLy;
Xuat;
END.
14
delete(s1,1,1);
if pos(s2,s1)=0 then inc(k)
end;
end;
writeln(fout,k);
end;
{-------------------------}
BEGIN
assign(fin,fi); reset(fin);
assign(fout,fo); rewrite(fout);
while not eof(fin) do
begin
readln(fin,s);
l:=length(s);
dem;
end;
Close(fin);
Close(fout);
END.
15
* Đọc file CAKE.INP, dùng mảng 1 chiều S[1..n] of char để ghi lại
các hạt viền quanh bánh. S[i] = ‘D’ là tại vị trí i có dâu, S[i] = ‘N’ là tại vị
trí i có nho. Đồng thời dùng biến Sd đếm số hạt dâu.
* Nếu n lẻ hoặc Sd lẻ thì kết quả ghi -1 vào file CAKE.OUT
* Ngược lại, tiến hành như sau: kiểm tra mọi phần bánh có chứa n
div 2 số hạt, nếu có đúng Sd div 2 hạt dâu thì đó là một phần bánh trong kết
quả (đây là bài toán duyệt mảng một chiều và đếm số phần tử thỏa một tính
chất nào đó).
Để kiểm tra mọi phần bánh có n div 2 số hạt ta chỉ cần kiểm tra các
đoạn hạt từ vị trí i đến j = i + n div 2-1, với i từ 1 đến n div 2.
* Chương trình:
Program ChiaBanh;
Uses Crt;
Const
fi='Cake.inp';
fo='Cake.out';
Var
S:array[1..256] of char;
f:text;
n,dau:integer;
{---------------------}
Procedure Nhap;
Var
ch:char;
i:integer;
Begin
assign(f,fi); reset(f);
readln(f,n);
for i:=1 to n do S[i]:='N';
for i:=1 to n do
begin
read(f,ch);
if ch='D' then inc(dau);
S[i]:=ch;
end;
Close(f);
End;
{-------------------}
Function CatDuoc(i,j:integer):boolean;
Var k,Sd,Sn:integer;
Begin
Sd:=dau div 2;
for k:=i to j do
16
if S[k]='D' then dec(Sd);
CatDuoc:=(Sd=0);
End;
{------------------}
Procedure XuLy;
Var i,j,c: integer;
Begin
assign(f,fo); rewrite(f);
if (n mod 2=1) or (dau mod 2=1) then
begin
write(f,-1);
Close(f);
halt;
end;
c:=n div 2;
for i:=1 to c do
begin
j:=i+c-1;
if CatDuoc(i,j) then
begin
write(f,i,' ',j);
Close(f);
halt;
end;
end;
write(f,-1);
Close(f);
End;
{---------------------}
BEGIN
dau:=0;
Nhap;
XuLy;
END.
17
+ Dòng thứ i trong số N dòng tiếp theo chứa số hạng ai của dãy số
đã cho (-32767 <= ai <= 32767, i = 1, 2, …, N).
- Kết quả: file văn bản DAYSO.OUT. Dòng đầu tiên ghi số lượng
phép đổi chỗ cần được thực hiện k (quy ước k = -1 nếu không thể biến đổi
được dãy đã cho thành dãy thỏa mãn yêu cầu đầu bài); nếu k > 0 thì dòng
thứ j trong số k dòng tiếp theo ghi chỉ số của 2 số hạng cần đổi chỗ cho
nhau ở lần đổi chỗ thứ j (j = 1, 2, …, k).
- Ví dụ:
DAYSO.INP DAYSO.OUT DAYSO.INP DAYSO.OUT
6 1 4 -1
1 5 6 1
2 3
3 2
4 5
6
5
18
begin
assign(f,fi); reset(f);
d1:=0; d2:=0;
readln(f,n);
for i:=1 to n do
begin
readln(f,x);
if x mod 2=0 then
if i mod 2=0 then A[i]:=0 else
begin
A[i]:=2;
inc(d2);
end;
if x mod 2=1 then
if i mod 2=1 then A[i]:=0 else
begin
A[i]:=1;
inc(d1);
end;
end;
Close(f);
end;
{------------------------}
procedure XuLy;
var i,j,k:integer;
begin
assign(f,fo); Rewrite(f);
if d1<>d2 then
begin
write(f,-1);
Close(f);
halt;
end;
writeln(f,d1);
for k:=1 to d1 do
begin
i:=1; j:=1;
while A[i]<>1 do inc(i);
while A[j]<>2 do inc(j);
if (A[i]=1) and (A[j]=2) then
begin
A[i]:=0; A[j]:=0;
if i<j then write(f,i,' ',j) else write(f,j,'
',i);
19
end;
end;
Close(f);
end;
{-------------------------}
BEGIN
Nhap;
XuLy;
END.
22
Xuat;
END.
23
- Khả năng 2: Chọn gói ở vị trí k - 1 (nếu k - 1 = 0 thì chọn gói N)
và các gói tiếp theo tính theo chiều ngược chiều kim đồng hồ cách quãng
từng gói một.
Từ đó, suy ra tổng số kẹo người thứ hai lấy được nhiều nhất là số
lớn nhất trong hai số thu được tương ứng với 2 khả năng trên.
Tuy nhiên, có thể mở rộng bài toán này theo hướng sau: trong cụm
từ “vị trí ngay sát cạnh” có thể hiểu “vị trí” theo nghĩa tương đối, nghĩa là
sau mỗi lần bớt đi 1 gói kẹo thì 2 gói đang cách nhau (bởi gói kẹo bớt đi)
lại trở thành sát cạnh nhau. Hiểu như vậy thì đây là bài toán phức tạp, có
thể giải bằng đệ quy với kích thước bài toán không lớn lắm.
* Chương trình:
Program TroChoi;
Uses Crt;
Const
fi='Game.inp';
fo='Game.out';
max=1000;
Type
mang=array[0..max] of integer;
Var
f:text;
a,diem:mang;
n,bd:integer;
tong1,tong2:longint;
{----------------}
procedure Nhap;
var i:integer;
begin
assign(f,fi); reset(f);
readln(f,n);
readln(f,bd);
bd:=bd-1;
diem[bd]:=1;
for i:=0 to n-1 do readln(f,a[i]);
Close(f);
end;
{------------------}
procedure KhaNang1;
var i:integer;
begin
i:=(bd+1) mod n;
repeat
tong1:=tong1+a[i];
24
diem[i]:=1;
i:=(i+2) mod n
until diem[i]=1;
end;
{-------------------}
procedure KhaNang2;
var i:integer;
begin
FillChar(diem,SizeOf(diem),0);
diem[bd]:=1;
i:=(bd-1) mod n;
if i<0 then i:=n-abs(i);
repeat
tong2:=tong2+a[i];
diem[i]:=1;
i:=(i-2) mod n;
if i<0 then i:=n-abs(i);
until diem[i]=1;
end;
{-------------------}
procedure Xuat;
var max:longint;
begin
assign(f,fo); rewrite(f);
max:=tong2;
if tong1>tong2 then max:=tong1;
writeln(f,max);
Close(f);
end;
{------------------}
BEGIN
Nhap;
KhaNang1;
KhaNang2;
Xuat;
END.
25
1
2 3
5
4 6
7 10
11 15
16 21
22 28
29 36
- Yêu cầu: Cho chỉ số của 2 điểm thuộc lưới tam giác nói trên. Hãy
viết chương trình xác định 2 điểm đó có thể là đỉnh của một tam giác chuẩn
hay không. Trong trường hợp câu trả lời là có thì xác định chỉ số điểm thứ
3 để bộ 3 điểm ấy lập thành một tam giác chuẩn.
- Dữ liệu vào: file văn bản TAMGIAC.INP có cấu trúc như sau:
+ Dòng đầu tiên chứa N là số các cặp điểm cần xem xét.
+ Mỗi dòng trong N dòng tiếp theo chứa 2 số là chỉ số của cặp
điểm tương ứng đã cho, các số được đặt cách nhau một dấu cách.
- Kết quả: file văn bản TAMGIAC.OUT gồm N dòng tương ứng
với N cặp điểm đã cho. Mỗi dòng trong N dòng đó bắt đầu bằng số 1 hoặc
0 tùy theo hai điểm đã cho tương ứng có thể là hai đỉnh của một tam giác
chuẩn hay không. Trong trường hợp câu trả lời là có thì số tiếp theo là chỉ
số của đỉnh thứ ba tìm được. Các số cần đặt cách nhau một dấu cách.
- Ví dụ:
TAMGIAC.INP TAMGIAC.OUT
4 1 3
1 2 1 16
7 18 0
1 5 1 13
4 6
- Gợi ý và lời giải:
* Coi mặt phẳng chứa tam giác như một mặt phẳng tọa độ, góc tọa
độ O(0, 0) là đỉnh trên của tam giác (đỉnh có chỉ số 1). Trục hoành là trục
Oi (chứa cạnh trái tam giác), trục tung là trục Oj (chứa cạnh phải của tam
giác). Cần xây dựng 2 chương trình con CTC1 và CTC2:
26
- CTC1: chuyển chỉ số của một điểm lưới thành tọa độ. Ví dụ, điểm
7 = (3, 0), 8 = (2, 1), 9 = (1, 2), 25 = (3, 3) …
- CTC2: làm nhiệm vụ ngược lại, khi biết tọa độ của một điểm
lưới, tìm chỉ số của điểm lưới này.
Giả sử, đọc từ file dữ liệu được 2 chỉ số của một cặp điểm là x và y.
Không mất tính tổng quát, giả sử x < y. Dùng CTC1 có x = (j1, i1) và y =
(j2, i2), (i1, i2 là tung độ; j1, j2 là hoành độ). Xảy ra 3 tình huống:
- Nếu i1 = i2 (2 điểm x và y nằm trên 2 đường thẳng song song với
Oj) thì điểm thứ 3 cần tìm là z = y + j2 + j1.
- Nếu j1 = j2 (2 điểm x và y nằm trên 2 đường thẳng song song với
Oi) thì điểm thứ 3 cần tìm là z = y - (i2 - i1).
- Nếu i1 + j1 = i2 + j2 (2 điểm x và y nằm trên đường thẳng nằm
ngang cùng phương đường thẳng nối điểm 11 với điểm 15 chẳng hạn) thì
điểm thứ 3 có tọa độ là (i2, j1). Dựa vào CTC2 sẽ tìm được z.
X=(i1, j1) X=(i1, j1) X=(i1, j1) Y=(i2, j2)
* Chương trình:
Program TamGiacChuan;
Uses Crt;
Const
fi='Tamgiac.inp';
fo='Tamgiac.out';
max=200;
Var
f1,f2:text;
x,y,z:longint;
d,c,i1,i2,j1,j2:integer;
{------------------------}
procedure CTC1(x:longint; var d,c:integer);
var i,j:integer;
p:longint;
Begin
i:=0; j:=0; p:=1;
while p<x do
begin
inc(j);
27
p:=p+j;
end;
if p>x then
begin
p:=p-j;
dec(j);
end;
while p<>x do
begin
p:=p+1;
dec(j);
inc(i);
end;
d:=i;
c:=j;
End;
{----------------------}
Function CTC2(x,y:integer):longint;
var j:integer;
p:longint;
Begin
j:=0; p:=1;
while j<x+y do
begin
inc(j);
p:=p+j;
end;
CTC2:=p+x;
End;
{---------------------}
procedure TimZ(x,y:integer; var z:longint);
Begin
CTC1(x,i1,j1);
CTC1(y,i2,j2);
if i1=i2 then z:=y+(j2-j1) else
if j1=j2 then z:=y-(i2-i1) else
if i1+j1=i2+j2 then z:=CTC2(i2,j1) else z:=0;
End;
{---------------------}
procedure XuLy;
procedure HoanVi(var x,y:longint);
var coc:longint;
begin
coc:=x;
28
x:=y;
y:=coc;
end;
Begin
assign(f1,fi); reset(f1);
assign(f2,fo); rewrite(f2);
readln(f1);
while not eof(f1) do
begin
readln(f1,x,y);
if x>y then HoanVi(x,y);
TimZ(x,y,z);
if z>0 then writeln(f2,1,' ',z) else writeln(f2,0);
end;
Close(f1);
Close(f2);
End;
{-------------------------}
BEGIN
XuLy;
END.
30
readln(f,c,d,e,g);
for i:=c to e do
for j:=d to g do h[i,j]:=1;
end;
Close(f);
End;
{-------------------}
Function KiemTra1(i,j:byte):boolean;
var d,c:byte;
Begin
KiemTra1:=false;
for d:=i to i+a-1 do
for c:=j to j+b-1 do
if h[d,c]<>0 then exit;
KiemTra1:=true;
End;
{-------------------}
Function KiemTra2(i,j:byte):boolean;
var d,c:byte;
Begin
KiemTra2:=false;
for d:=i to i+b-1 do
for c:=j to j+a-1 do
if h[d,c]<>0 then exit;
KiemTra2:=true;
End;
{--------------------}
procedure Tim;
var i,j:byte;
Begin
sn:=0;
for i:=1 to m do
for j:=1 to n do
if h[i,j]=0 then
begin
kl:=0;
ok:=KiemTra1(i,j);
if ok then
begin
inc(sn);
kl:=1;
li:=i;
lj:=j;
exit;
31
end
else
begin
kl:=0;
ok:=KiemTra2(i,j);
if ok then
begin
inc(sn);
kl:=2;
li:=i;
lj:=j;
exit;
end;
end;
end;
End;
{----------------------}
procedure Xuat;
var i,j:byte;
Begin
assign(f,fo); rewrite(f);
if sn=0 then write(f,0) else
begin
writeln(f,1);
if kl=1 then write(f,li,' ',lj,' ',li+a-1,'
',lj+b-1)
else
if kl=2 then write(f,li,' ',lj,' ',li+b-1,'
',lj+a-1);
end;
Close(f);
End;
{---------------------}
BEGIN
Nhap;
Tim;
Xuat;
END.
32