Tải bản đầy đủ (.doc) (34 trang)

Giải bài toán pascal bằng pp hình học

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (298.34 KB, 34 trang )

PHƯƠNG PHÁP GIẢI TOÁN HÌNH HỌC BẰNG NNLT PASCAL
I. KHÁI NIỆM HÌNH HỌC VÀ CÁC ĐỐI TƯỢNG HÌNH HỌC CƠ BẢN
1. Khái niệm hình học
Đa số các thuật toán đều tập trung vào văn bản và các con số, chúng được
thiết kế và xử lý sẵn trong phần lớn các môi trường lập trình. Đối với các bài toán
hình học thì tình huống khác hẳn, ngay cả các phép toán sơ cấp trên điểm và đoạn
thẳng cũng có thể là một thách thức về tính toán.
Các bài toán hình học thì dễ hình dung một cách trực quan nhưng chính điều
đó lại có thể là một trở ngại. Nhiều bài toán có thể giải quyết ngay lập tức bằng
cách nhìn vào một mảnh giấy nhưng lại đòi hỏi những chương trình không đơn
giản.
VÝ dô: Bµi to¸n kiÓm tra mét ®iÓm cã n»m trong ®a gi¸c hay kh«ng?
2. Đối tượng hình học cơ bản.
Trong các bài toán tin học thuộc loại hình học có 3 đối tượng cơ bản là:
Điểm, đoạn thẳng và đa giác.
- Điểm: Được xác định là cặp (x,y) trong hệ toạ độ đề các.
- Đoạn thẳng: Là cặp điểm được nối với nhau bằng một phần của đường
thẳng.
- Đa giác: Là dãy các điểm mà 2 điểm liên tiếp nối với nhau bởi đoạn thẳng
và điểm đầu nối với điểm cuối tạo thành đường gấp khúc khép kín.
3. Dữ liệu lưu trữ các đối tượng hình học cơ bản
Type
point = record x,y: integer; end;
Line = record p1,p2: point; end;
Var Polygon: Array[0 Nmax] of Point;
II. MỘT SỐ PHÉP TOÁN CƠ BẢN
1. Vị trí tương đối của điểm so với đường thẳng, tia và đoạn thẳng
Bài toán 1: Cho điểm M(x
0
,y
0


), A(x
A
,y
A
), B(x
B
,y
B
). Yêu cầu:
a) Kiểm tra M có thuộc đường thẳng đi qua 2 điểm A, B hay không?
b) Kiểm tra M có thuộc đoạn thẳng AB hay không
c) Kiểm tra M có thuộc tia AB hay không
• Phương pháp:
Đặt F(X,Y) = (y
A
-y
B
)X + (x
B
-x
A
)Y + (x
A
y
B
- x
B
y
A
)

- Điểm M thuộc đường thẳng AB khi F(x
0
,y
0
) = 0
- Điểm M thuộc đoạn thẳng AB khi:
F(x
0
,y
0
)=0 và Min(x
A
,x
B
)

x
0

Max(x
A
,x
B
) và Min(y
A
,y
B
)

y

0


Max(y
A
,y
B
)
1
- Điểm M thuộc tia AB khi F(x
0
,y
0
) = 0 và
ABkAM =
có nghĩa là M phải thoả
mãn điều kiện: F(x
0
,y
0
) = 0 và (x
0
-x
A
)(x
B
-x
A
)


0 và (y
0
-y
A
)(y
B
-y
A
)

0
• Chương trình:
var xa,ya,xb,yb,xo,yo:real;
procedure nhap;
begin
repeat
write('nhap toa do diem A:'); readln(xa,ya);
write('nhap toa do diem B:'); readln(xb,yb);
until (xa<>xb) or (ya<>yb);
write('nhap toa do diem M:'); readln(xo,yo);
end;
{=============}
Function F(xo,yo:real):real;
begin
F:= (ya-yb)*xo+(xb-xa)*yo +(xa*yb - xb*ya);
end;
{=============}
Function Max(a,b:real):Real;
begin
if a>b then Max:=a else Max:=b;

end;
{=============}
Function Min(a,b:real):Real;
begin
if a>b then Min:=b else Min:=a;
end;
{====Kiem tra M thuoc duong thang, doan thang, tia===}
Begin
nhap;
if F(xo,yo)=0 then writeln('M thuoc duong thang AB')
else writeln('M ko thuoc duong AB');
if (F(xo,yo)=0) and (min(xa,xb)<=xo) and (xo<=max(xa,xb)) and
(min(ya,yb)<=yo) and (yo<=max(ya,yb))
then writeln('M thuoc doan thang AB') else writeln('M khong thuoc doan
thang AB');
if (F(xo,yo)=0) and ((xo-xa)*(xb-xa)>=0) and ((yo-ya)*(yb-ya)>=0)
then writeln('M thuoc tia AB') else writeln('M khong thuoc tia AB');
readln;
End.
2. Giao của các đoạn thẳng, đường thẳng và tia
Bài toán 2. Cho 2 đường thẳng có phương trình a
1
x+b
1
y+c
1
=0 và a
2
x+b
2

y+c
2
=0. Tìm
giao điểm (nếu có) của 2 đường thẳng trên.
•Phương pháp:
B
1
. Tính D = a
1
b
2
- a
2
b
1
, Dx = c
2
b
1
- c
1
b
2
, Dy = a
2
c
1
- a
1
c

2
B
2
. Xét 3 khả năng:
+ Nếu D=Dx=Dy=0 thì kết luận 2 đường thẳng trùng nhau
+ Nếu D=0 và ((Dx≠0) hoặc (Dy≠0)) thì kết luận 2 đường thẳng song song
+ Nếu D≠0 thì kết luận 2 đường thẳng cắt nhau tại điểm có (Dx/D, Dy/D)
• Chương trình:
var a1,b1,c1,a2,b2,c2,D,Dx,Dy:real;
{============}
procedure nhap;
begin
write('nhap he so cua dt 1 a1,b1,c1:'); readln(a1,b1,c1);
write('nhap he so cua dt 2 a2,b2,c2:'); readln(a2,b2,c2);
end;
{=============}
Begin
2
nhap;
D:=a1*b2-a2*b1; Dx:=c2*b1-c1*b2; Dy:=a2*c1-a1*c2;
if (D=0)and(Dx=0)and(Dy=0) then write('2 duong thang trung nhau')
else
if (D=0)and((Dx<>0)or(Dy<>0)) then write('2 duong thang song song')
else write('2 d/thang cat nhau tai M(',Dx/D:5:2,',',Dy/D:5:2,')');
readln;
End.
Bài toán 3. Cho 2 đoạn thẳng AB và CD với A(x
1
,y
1

), B(x
2
,y
2
), C(x
3
,y
3
),
D(x
4
,y
4
). Tìm giao điểm (nếu có) của 2 đoạn thẳng
• Phương pháp:
B
1
. Tìm giao điểm M của 2 đường thẳng AB và CD
B
2
. Kiểm tra M có thuộc đồng thời cả 2 đoạn AB và CD hay không. Nếu có đó
là giao điểm cần tìm, ngược lại kết luận không có.
• Chương trình:
var xa,ya,xb,yb,xc,yc,xd,yd:real; a1,b1,c1,a2,b2,c2,D,Dx,Dy:real;
{============}
procedure nhap;
begin
repeat
write('nhap toa do diem A:'); readln(xa,ya);
write('nhap toa do diem B:'); readln(xb,yb);

write('nhap toa do diem C:'); readln(xc,yc);
write('nhap toa do diem D:'); readln(xd,yd);
until ((xa<>xb) or (ya<>yb)) and ((xa<>xb) or (ya<>yb));
end;
{=============}
Function Max(a,b:real):Real;
begin
if a>b then Max:=a else Max:=b;
end;
{=============}
Function Min(a,b:real):Real;
begin
if a>b then Min:=b else Min:=a;
end;
{===Kiem tra M thuoc doan ==}
Function Ktra(xo,yo,xa,ya,xb,yb:real):boolean;
begin
if (min(xa,xb)<=xo) and (xo<=max(xa,xb))
and (min(ya,yb)<=yo) and (yo<=max(ya,yb))
then Ktra:=true else Ktra:=false;
end;
{===Tim giao diem neu co ===}
procedure Xac_dinh;
begin
a1:=yb-ya; b1:=xa-xb; c1:=ya*xb-xa*yb;
a2:=yd-yc; b2:=xc-xd; c2:=yc*xd-xc*yd;
D:=a1*b2-a2*b1; Dx:=c2*b1-c1*b2; Dy:=a2*c1-a1*c2;
if(D<>0)and(ktra(Dx/D,Dy/D,xa,ya,xb,yb))and ktra(Dx/D,Dy/D,xc,yc,xd,yd))
then writeln('2 d/thang cat nhau tai M(',Dx/D:5:2,',',Dy/D:5:2,')')
else write('Hai doan thang khong cat nhau');

end;
{==============}
Begin
nhap;
Xac_dinh;
readln;
End.
Bài toán 4. Cho tia AM chứa điểm B (khác A) và đoạn thẳng CD với A(x
1
,y
1
),
B(x
2
,y
2
), C(x
3
,y
3
), D(x
4
,y
4
). Tìm giao điểm (nếu có) của tia AM với đoạn thẳng CD.
3
• Phương pháp:
B
1
. Tìm giao điểm N của 2 đường thẳng AB và CD

B
2
. Kiểm tra N có thuộc tia AM và đoạn thẳng CD hay không. Nếu có đó là
giao điểm cần tìm, ngược lại kết luận không có.
• Chương trình:
var xa,ya,xb,yb,xc,yc,xd,yd:real; a1,b1,c1,a2,b2,c2,D,Dx,Dy:real;
{============}
procedure nhap;
begin
repeat
write('nhap toa do diem A:'); readln(xa,ya);
write('nhap toa do diem B:'); readln(xb,yb);
write('nhap toa do diem C:'); readln(xc,yc);
write('nhap toa do diem D:'); readln(xd,yd);
until ((xa<>xb) or (ya<>yb)) and ((xa<>xb) or (ya<>yb));
end;
{=============}
Function Max(a,b:real):Real;
begin
if a>b then Max:=a else Max:=b;
end;
{=============}
Function Min(a,b:real):Real;
begin
if a>b then Min:=b else Min:=a;
end;
{===Kiem tra M thuoc doan ==}
Function Ktra(xo,yo,xa,ya,xb,yb:real):boolean;
begin
if (min(xa,xb)<=xo) and (xo<=max(xa,xb))

and (min(ya,yb)<=yo) and (yo<=max(ya,yb))
then Ktra:=true else Ktra:=false;
end;
{===Tim giao diem===}
procedure Xac_dinh;
begin
a1:=yb-ya; b1:=xa-xb; c1:=ya*xb-xa*yb;
a2:=yd-yc; b2:=xc-xd; c2:=yc*xd-xc*yd;
D:=a1*b2-a2*b1; Dx:=c2*b1-c1*b2; Dy:=a2*c1-a1*c2;
if (D<>0) and (ktra(Dx/D,Dy/D,xc,yc,xd,yd))
and ((Dx/D-xa)*(xb-xa)>=0) and ((Dy/D-ya)*(yb-ya)>=0)
then writeln('Tia AM cat doan thang CD tai M(',Dx/D:5:2,',',Dy/D:5:2,')')
else write('Tia AM khong cat doan thang CD');
end;
{==============}
Begin
nhap;
Xac_dinh;
readln;
End.
3. Vị trí của điểm so với đa giác
Bài toán 5. Cho đa giác gồm N đỉnh d
1
, d
2
, ,d
N
và điểm M. Xác định vị trí
tương đối của M với miền trong đa giác.
Phương pháp:

B
1
. Kiểm tra M có thuộc cạnh nào của đa giác hay không, nếu có thì kết luận
M thuộc miền trong đa giác và kết thúc
B
2
. Kẻ MN song song với trục hoành (điểm N có hoành độ lớn hơn max hoành
độ của đa giác)
4
B
3
. Xác định d là số giao điểm của MN với các cạnh của đa giác. Những
trường hợp sau được coi như là tăng thêm 1 giao điểm:
+ Đỉnh d[i] không thuộc đoạn thẳng MN, đỉnh d[i+1] nằm trên đoạn thẳng
MN, 2 đỉnh d[i] và d[i+2] khác phía so với đường thẳng MN.
+ Đỉnh d[i-1], d[i+2] ngoài đoạn thẳng MN, hai đỉnh d[i] và d[i+1] thuộc đoạn
MN, d[i-1] và d[i+1] khác phía so với đường thẳng MN
+ Đỉnh d[i] và d[i+1] không thuộc MN và cạnh (d[i],d[i+1]) cắt đoạn thẳng
MN
III. MỘT SỐ DẠNG BÀI TOÁN HÌNH HỌC THƯỜNG GẶP
Dạng 1. Mối quan hệ giữa điểm, đoạn thẳng, đa giác.
Phương pháp: Đây là một trong số dạng bài toán hình học đơn giản nhất.
Việc giải bài toán dạng này chủ yếu sử dụng các kiến thức hình học cơ bản (đã
trình bày đầy đủ trong phần trên)

VD
1
. Ba điểm thẳng hàng
Cho N điểm, hãy kiểm tra xem có bao nhiêu bộ 3 điểm
thẳng hàng.

Input: Cho trong tệp văn bản DL.Inp
- Dòng thứ 1 ghi số N
- N dòng tiếp theo, mỗi dòng ghi toạ độ của một điểm.
Output: Ghi vào tệp KQ.OuT chứa một số duy nhất là số bộ 3 điểm thẳng hàng.
(Giới hạn: 1<=N<=2000, toạ độ các điểm có giá trị tuyệt đối không quá 10000)
• Chương trình:
const maxn=2000;
type td=record x,y:integer; end;
var a: array[1 maxn] of td;
free:array[1 maxn] of boolean;
n,i:integer; c:longint; f:text;
{=======================================}
Procedure DocDL;
begin
assign(f,'DL.INP'); reset(f); readln(f,n);
for i:=1 to n do readln(f,a[i].x,a[i].y);
close(f);
end;
{======================================}
Procedure Dem;
var j,k,x1,y1,tmp:integer;
begin
c:=0;
for i:=1 to n-1 do
begin
fillchar(free,sizeof(free),true);
for j:=i+1 to n-1 do
if free[j] then
begin
DL.

NP
KQ.OUT
6
0 0
0 1
0 2
1 1
1 2
2 2
3
5
tmp:=1;
x1:=a[j].x-a[i].x; y1:=a[j].y-a[i].y;
for k:=j+1 to n do
if free[k] then
if x1*(a[k].y-a[i].y)=y1*(a[k].x-a[i].x) then
begin
inc(tmp);
free[k]:=false;
end;
inc(c,tmp*(tmp-1) div 2);
end;
end;
end;
{========================================}
procedure Xuat;
begin
assign(f,'KQ.OUT'); rewrite(f); writeln(f,c); close(f);
end;
{====================================}

Begin
DocDL; Dem; Xuat;
End.
VD
2
. Đường thẳng cắt nhau
Cho n đường thẳng A
i
B
i
(1≤i≤n) phân biệt với A
i
, B
i
là các điểm cho trước.
Hãy thông báo ra màn hình các cặp đường thẳng đôi một cắt nhau.
Dữ liệu: Cho trong file DL.INP gồm N dòng (N không biết trước). Dòng thứ
i ghi 4 số thực x
Ai
y
Ai
x
Bi
y
Bi
. Các số trên cùng một
dòng ghi cách nhau ít nhất một dấu cách.
• Ý tưởng:
- Mỗi đường thẳng được đặc trưng bởi 3 thông số a,b,c được xác định:
a:=(y1-y2); b:=(x2-x1) ; c:=x1*y2-x2*y1;

- Hai đường thẳng cắt nhau khi: D:=a1*b2-a2*b1 ? 0;
• Chương trình:
type dthang=record x1,y1,x2,y2:integer; end;
heso=record a,b,c:integer; end;
var pt:array[1 100] of heso;
f:text; n:integer;
{============}
procedure doc_DL;
var i,x1,y1,x2,y2:integer;
begin
i:=0;
assign(f,'dt.inp');reset(f);
while not eof(f) do
begin
i:=i+1;
readln(f,x1,y1,x2,y2);
pt[i].a:=(y1-y2);
pt[i].b:=(x2-x1) ;
pt[i].c:=x1*y2-x2*y1;
end;
n:=i;
close(f);
end;
{===Kiem tra 2 duong thang cat nhau ==}
Function Ktra(pt1,pt2:heso):boolean;
var D:integer;
begin
D:=pt1.a*pt2.b-pt2.a*pt1.b;
if D<>0 then ktra:=true else Ktra:=false;
end;

DL.INP KÕt qu¶
0 0 1 1
0 1 1 2
-1 -1 8 9
§/th¼ng 1 c¾t ®/th¼ng 3
§/th¼ng 2 c¾t ®/th¼ng 3
6
{===Tim giao diem===}
procedure Xac_dinh;
var i,j:integer; kt:boolean;
begin
kt:=false;
For i:=1 to n-1 do
For j:=i+1 to n do
if ktra(pt[i],pt[j]) then
begin
writeln('Duong thang',i,'cat duong thang',j);
kt:=true;
end;
if not kt then writeln('khong co cap duong thang cat nhau')
end;
{==============}
Begin
doc_DL;
Xac_dinh;
readln;
End.
VD
3
. Điểm thuộc đa giác.

Cho đa giác không tự cắt A
1
A
2
A
N
với các đỉnh A
i
(x
i
,y
i
) nguyên. Với điểm
A(x
A
,y
A
) cho trước, hãy xác định xem A có nằm trong đa giác đã cho hay không
(Trong trường hợp trên cạnh đa giác xem như nằm trong đa giác)
Dữ liệu: Cho trong tệp Dagiac.inp
+ Dòng đầu là số N
+ N dòng tiếp theo mỗi dòng ghi x
i
,y
i
là toạ độ A
i
+ Dòng n+2 ghi 2 số x
A
và y

A
Dữ liệu là các số nguyên.
Kết quả: Đưa ra màn hình thông báo điểm A có nằm trong đa giác hay không
• Ý tưởng:
- Lưu toạ độ các đỉnh đa giác vào mảng A
- Kiểm tra xem điểm A có trùng với đỉnh đa giác
- Kiểm tra xem điểm A có nằm trên cạnh đa giác
- Tìm giao điểm nếu có của tia Ax (Ax//Ox và Ax hướng theo phần dương
trục hoành) với các cạnh của đa giác. Trường hợp tia Ax chứa đoạn thẳng cạnh đa
giác ta xem như tia Ax có 1 điểm chung với cạnh này. Cụ thể:
+ Giả sử điểm A(x
0
,y
0
), chọn điểm B(x
b
,y
b
) với x
b
=x
0
+1,y
b
=y
0
+ Kiểm tra tia AB có cắt đoạn thẳng CD bằng cách:
B
1
. Tìm giao điểm N của 2 đường thẳng AB và CD

• Tính
a1:=yb-ya; b1:=xa-xb; c1:=ya*xb-xa*yb;
a2:=yd-yc; b2:=xc-xd; c2:=yc*xd-xc*yd;
D:=a1*b2-a2*b1; Dx:=c2*b1-c1*b2; Dy:=a2*c1-a1*c2;
• Xác định: Nếu D≠0 thì toạ độ giao điểm là N(Dx/D,Dy/D)
B
2
. Kiểm tra N có thuộc tia AM và đoạn thẳng CD hay không.
Dagiac.inp KÕt qu¶
5
0 0
2 0
0 3
-2 2
-3 -2
10 10
§iÓm A(10,10)
kh«ng n»m trong ®a gi¸c
7
- Điểm N thuộc đoạn thẳng CD khi: Min(x
C
,x
D
)≤x
N
≤ Max(x
C
,x
D
) và

Min(y
C
,y
D
)≤ y
N
≤ Max(y
C
,y
D
)
- Điểm N thuộc tia AB khi
ABkAN =
có nghĩa là N phải thoả mãn điều
kiện: (x
N
-x
A
)(x
B
-x
A
)≥0 và (y
N
-y
A
)(y
B
-y
A

)≥0
+ Kiểm tra tia AB chưa cạnh CD hay không bằng cách: (yc=yd)and(yc=yo)
- Đếm số giao điểm, nếu số giao điểm lẻ thì A thuộc đa giác
• Chương trình:
const maxn=100;
Type xy=record x,y:real; end;
var n:byte;
A:array[1 maxn+2] of xy;
a1,a2,x1,x2,y1,y2,b1,b2, c1,c2,D,Dx,Dy:Real;
k,dem,dem1,i:integer;
{===================================}
procedure Doc_DL;
var f:text;
begin
assign(f,'DL.INP'); reset(f); readln(f,n);
fillchar(A,Sizeof(A),0);
for i:=1 to n do readln(f,A[i].x,A[i].y);
readln(f,A[N+2].x,A[n+2].y);
A[n+1]:=A[1]; close(f);
end;
{======================================}
function kiemtradinh:boolean;
begin
kiemtradinh:=true;
for i:=1 to n do
if (A[i].x=A[n+2].x) and (A[i].y=A[n+2].y) then exit;
kiemtradinh:=false;
end;
{========================================}
function kiemtracanh:boolean;

begin
kiemtracanh:=true;
for i:=1 to n do
if A[n+2].x*(A[i].y-A[i+1].y)+A[n+2].y*(A[i+1].x-A[i].x)
+ A[i].x*A[i+1].y-A[i].y*A[i+1].x=0 then exit;
kiemtracanh:=false;
end;
{=============================================}
{=== Kiem tra Ax co chua canh da giac hay cat canh da giac===}
Function kiemtra_giaodiem(xo,yo,xc,yc,xd,yd:real):boolean;
var xa,ya,xb,yb:real;
{===Kiem tra diem thuoc doan thuoc doan ==}
Function Ktra(xo,yo,xa,ya,xb,yb:real):boolean;
var max1,min1,max2,min2:real;
begin
if xa>xb then begin Max1:=xa;min1:=xb end else begin Max1:=xb;min1:=xa; end;
if ya>yb then begin Max2:=ya;min2:=yb end else begin Max2:=yb;min2:=ya; end;
if (min1<=xo) and (xo<=max1) and (min2<=yo) and (yo<=max2)
then Ktra:=true else Ktra:=false;
end;
{===Tim giao diem===}
begin
xa:=xo;ya:=yo;xb:=xo+1;yb:=yo; a1:=yb-ya; b1:=xa-xb; c1:=ya*xb-xa*yb;
a2:=yd-yc; b2:=xc-xd; c2:=yc*xd-xc*yd;
D:=a1*b2-a2*b1; Dx:=c2*b1-c1*b2; Dy:=a2*c1-a1*c2;
8
if ((D<>0) and (ktra(Dx/D,Dy/D,xc,yc,xd,yd)) and ((Dx/D-xa)*(xb-xa)>=0) and
((Dy/D-ya)*(yb-ya)>=0))
or ((yc=yd)and(yc=yo))
then kiemtra_giaodiem:=true else kiemtra_giaodiem:=false;

end;
{====================================}
function kiemtra:boolean;
begin
kiemtra:=true;
if kiemtradinh then exit;
if kiemtracanh then exit;
dem:=0; dem1:=0;
for i:=1 to n do
if kiemtra_giaodiem(A[N+2].x,A[n+2].y,A[i].x,A[i].y,A[i+1].x,A[i+1].y)
then Dem:=dem+1;
if dem mod 2=0 then kiemtra:=false;
end;
{==================================================}
BEGIN
Doc_DL;
if kiemtra then
write('Diem A(',a[n+2].x:0:2,',',A[n+2].y:0:2,') nam trong da giac')
else write('Diem A(',a[n+2].x:0:2,',',A[n+2].y:0:2,') khong nam trong
da giac');
readln;
end.
VD
4
. Đếm số điểm có toạ độ nguyên thuộc đa giác (Bài đã được đăng trên tạp
chí Tin học & Nhà trường số 04/2009)
Cho đa giác gồm n đỉnh (x
1
,y
1

), (x
2
,y
2
), , (x
n
,y
n
), biết (2<n<10
4
), x
i

y
i
(i=1, ,n) là các số nguyên trong đoạn [-10
6
,10
6
]. Các đỉnh
được liệt kê theo thứ tự cùng chiều kim đồng hồ. Viết
chương trình tìm số điểm có toạ độ nguyên nằm trong hay
trên biên đa giác.
Dữ liệu: Cho trong tệp tin DL.INP.
- Dòng đầu chứa số nguyên duy nhất cho biết số đỉnh.
- Tiếp theo là các dòng, trên mỗi dòng có 2 số nguyên cách nhau một khoảng
trắng lần lượt là hoành độ, tung độ các đỉnh đa giác.
Kết quả: Xuất ra màn hình số điểm có toạ độ nguyên nằm trong hay trên biên
đa giác
• Ý tưởng:

- Tính a,b theo công thức:
))(())((
11
2
11 nn
n
i
iiii
yyxxyyxxa +−++−=

=
−−
),(),(
11
2
11 nn
n
i
iiii
yyxxUCLNyyxxUCLNb −−+−−=

=
−−
- Xác định số điểm có toạ độ nguyên: Sđ=round(abs(a/2)+b/2+1)
•Chương trình:
Var N:longint; f:text;
x1,y1,xt,yt,x,y,i,b,sd,a:longint;
{================================}
Function UCLN(a,b:longint):longint;
var tg:longint;

DL.INP KQ.OUT
4
0 0
3 3
4 0
2 1
8
9
begin
while b>0 do
begin tg:=b; b:=a mod b; a:=tg; end;
UCLN:=a;
end;
{==========================================}
BEGIN
b:=0; a:=0;
assign(f,'dagiac.inp'); reset(f);
readln(f,n); readln(f,x,y);
x1:=x; y1:=y;
for i:=2 to n do
begin
xt:=x; yt:=y;
readln(f,x,y);
a:=a+(x-xt)*(y+yt);b:=b+UCLN(abs(x-xt),abs(y-yt));
end;
a:=a+(x1-x)*(y1+y);
b:=b+UCLN(abs(x1-x),abs(y1-y));
sd:=round(abs(a/2)+b/2+1);
writeln(sd);
close(f);

readln;
END.
Dạng 2. Tính diện tích đa giác
Phương pháp: Giả sử cho đa giác có n đỉnh và toạ độ các đỉnh lưu vào mảng
a. Để tính diện tích đa giác ta làm như sau:
Bước 1. Gắn thêm đỉnh phụ:
a[n+1].x:=a[1].x; a[n+1].y:=a[1].y;
Bước 2. Diện tích đa giác tính theo công thức:
2/)].[].1[)(].[].1[(
1
yiayiaxiaxiaS
n
i
++−+=

=
Lưu ý: Có thể áp dụng công thức khác để tính diện tích trong các trường
hợp đặc biệt.
- Nếu đa giác là tam giác (n=3) thì diện tích tính theo công thức:
S =
4/))()()(( acbbcacbacba −+−+−+++
- Nếu đa giác là hình chữ nhật (n=4) có các cạnh là a,b thì diện tích là: S=ab
- Nếu đa giác là hình vuông (n=4) có cạnh là a thì diện tích là: S=a
2
- Nếu đa giác là hình tròn có bán kính R thì diện tích là
2

VD
1
. Xác định diện tích đa giác

Cho N đa giác lồi A
1
A
2
A
3
A
N-1
A
N
với các đỉnh A
i
(x
i
,y
i
) có toạ độ nguyên.
Hãy tính diện tích đa giác trên.
Dữ liệu: Cho trong file DL.INP gồm 2 dòng
- Dòng 1: Chứa số nguyên dương N
- Dòng 2: Chứa 2xN số nguyên dương x
1
y
1
x
2
y
2
x
N

y
N
là toạ độ các đỉnh của
đa giác. Mỗi số ghi cách nhau một dấu cách.
Kết quả: Xuất ra màn hình diện tích đa giác.
•Ý tưởng:
- Lưu toạ độ các đỉnh đa giác vào mảng toado
DL.INP KQ
5
- 8 -8 0 0 1 0 -2 4 -5 0
44.00
10
- S dng cụng thc tớnh din tớch a giỏc:
for i:=1 to n do
s:=s+(Toado[i+1].x-Toado[i].x)*(Toado[i+1].y+toado[i].y)/2;
- Kt qu cn tỡm l abs(s)
Chng trỡnh:
const maxn=100;
type xy=record
x,y:integer; end;
var Toado:array[1 maxn+1] of xy;
n,i:integer; s:real;
Procedure Nhap;
var f:text;
begin
assign(f,'DL.TXT');
reset(f);
readln(f,n);
for i:=1 to n do read(f,Toado[i].x,toado[i].y);
close(f);

end;
{====================================}
procedure Dientich;
begin
s:=0;
Toado[n+1].x:=Toado[1].x;
Toado[n+1].y:=Toado[1].y;
for i:=1 to n do
s:=s+(Toado[i+1].x-Toado[i].x)*(Toado[i+1].y+toado[i].y)/2;
writeln('Dien tich da giac :', abs(s):0:2);
readln;
end;
Begin
Nhap;
Dientich;
End.
VD
2
. Dãy hình chữ nhật
Trong mt phng to trc chun, cho N hình ch nht có các cnh song
song vi trc to . Mi HCN c xác nh bi to nh di bên trái v nh
trên bên phi ca nó. Hãy đa ra dãy các hình chữ nhật theo thứ tự tăng dần diện tích
.
D liu: Cho trong file HCN.inp gm N+1 dòng.
- Dòng 1. Cha s N
-Dòng i+1 (1iN): Ghi 4 s nguyên x1,y1,x2,y2 ln lt l to nh
di bên trái v nh trên bên phi của HCN i. (Các s ghi trên mt dòng cách nhau
ít nht mt du cách)
Kt qu: Ghi vào tệp HCN.out dãy các hình chữ nhật sau khi sắp xếp.
ý tởng:

- Lu toạ độ các đỉnh đa giác vào mảng a
- Tính diện tích hình chữ nhật theo công thức:
))((
1212
yyxxs =
- Sắp xếp mảng a tăng dần theo diện tích
HCN.inp HCN.out
5
-3 -4 0 -2
-6 -4 0 0
-6 -2 -3 0
0 0 7 7
-6 0 0 7
-3 -4 0 -2
-6 -2 -3 0
-6 -4 0 0
-6 0 0 7
0 0 7 7
11
Chơng trình:
Type hcn=record x1,y1,x2,y2:integer; end;
var a:array[1 100] of hcn;
n:integer; f:text;
{=================}
procedure doc_dl;
var i:integer;
begin
assign(f,'HCN.inp'); reset(f); readln(f,n);
for i:=1 to n do readln(f,a[i].x1,a[i].y1,a[i].x2,a[i].y2);
close(f);

end;
{=================}
Function S(k:integer):longint;
begin
S:=abs((a[k].x2-a[k].x1)*(a[k].y2-a[k].y1));
end;
{=================}
procedure sapxep;
var i,j:integer;tg:hcn;
begin
for i:=1 to n-1 do
for j:=i+1 to n do
if s(i)>s(j) then
begin tg:=a[i]; a[i]:=a[j]; a[j]:=tg; end;
end;
{================}
procedure ketqua;
var i:integer;
begin
assign(f,'HCN.out'); rewrite(f);
for i:=1 to n do writeln(f,a[i].x1,' ',a[i].y1,' ',a[i].x2,' ',a[i].y2);
close(f);
end;
{===============}
begin
doc_dl; sapxep; ketqua;
end.
Dng 3. Xỏc nh din tớch ph bi cỏc hỡnh ch nht
Phng phỏp: Gi s cú n hỡnh ch nht. tớnh din tớch ph bi n hỡnh
ch nht ta lm nh sau:

Bc 1. S dng a,b ln lt l cỏc mng lu honh v tung cỏc nh
hỡnh ch nht (mi hỡnh ch nht ch cn lu to 2 nh i din qua tõm hỡnh
ch nht).
Bc 2. Sp xp mng a,b theo th t tng dn
Bớc 3. Ln lt kim tra cỏc hỡnh ch nht cú to nh trờn bờn phi
(x
i+1
,y
i+1
) v to nh di bờn phi l (x
i
,y
i
) vi 1in-1. Nu hỡnh ch nht ny
thuc mt trong cỏc hỡnh ch nht ban u thỡ cng thờm vo phn din tớch ang
cn tỡm din tớch ca hỡnh ch nht con ny.
VD
1
. Diện tích phủ bởi các hình chữ nhật (Bài đã đợc đăng trên tạp chí Tin học
& Nhà trờng số 02/2009)
Trong mt phng to trc chun, cho N hỡnh ch nht cú cỏc cnh song
song vi trc to . Mi HCN c xỏc nh bi to nh di bờn trỏi v nh
trờn bờn phi ca nú. Hóy tớnh din tớch phn mt phng b ph bi cỏc HCN trờn.
12
D liu: Cho trong file HCN.inp gm N+1 dũng.
- Dũng 1: Cha s N
-Dũng i+1 (1iN): Ghi 4 s nguyờn x1,y1,x2,y2 ln lt l to nh di
bờn trỏi v nh trờn bờn phi ca HCN i.
Cỏc s ghi trờn mt dũng cỏch nhau ớt nht mt du cỏch.
Kt qu: a ra mn hỡnh din tớch phn mt phng b ph bi hỡnh ch nht

trờn.
í tng:
- Lp mng X[1 2n], Y[1 2n] ln lt cha honh , tung cỏc hỡnh ch
nht
- Lu toạ độ ban đâu các hình chữ nhật vào mảng a
- Sp xp mng X,Y tng dn
- Ln lt kim tra cỏc hỡnh ch nht cú to nh trờn bờn phi (x
i+1
,y
i+1
)
v to nh di bờn phi l (x
i
,y
i
) vi 1in-1. Nu hỡnh ch nht ny thuc
mt trong cỏc hỡnh ch nht ban u thỡ cng thờm vo phn din tớch ang cn tỡm
din tớch ca hỡnh ch nht con ny.
Const Maxn=1000;
Type Toa_do = record x1,y1,x2,y2:integer; end;
mang=array[1 2*maxn] of integer;
var N,s:integer;
a:array[1 maxn] of toa_do;
X,Y:mang;
{=======Doc du lieu=====}
Procedure doc_dl;
var f:text; i:integer;
begin
assign(f,'HCN.inp'); reset(f);
readln(f,n);

for i:=1 to n do
readln(f,a[i].x1,a[i].y1,a[i].x2,a[i].y2);
close(f);
end;
{===Sap xep mang tang dan===}
Procedure Sapxep(Var T:Mang);
Var i,j,TG,m:integer;
Begin
m:=2*n;
for i:=1 to m-1 do
for j:=i+1 to m do
if T[i]>T[j] then
begin
TG:=T[i];
T[i]:=T[j];
T[j]:=TG;
end;
end;
{====Kiem tra HCN moi thuoc HCN da cho====}
function Kiemtra_thuoc(i,j:integer):boolean;
var k:integer;
begin
Kiemtra_thuoc:=true;
for k:=1 to N do
HCN.inp Kt qu
5
-3 -4 0 -2
-6 -4 0 0
-6 -2 -3 0
0 0 7 7

-6 0 0 7
115
13
if (a[k].x1<=x[i-1]) and (X[i]<=a[k].x2)
and (a[k].y1<=y[j-1]) and(Y[j]<=a[k].y2) then exit;
Kiemtra_thuoc:=false;
end;
{========================================}
Procedure Xuly;
var i,j:integer;
Begin
for i:=1 to N do
begin
X[i*2-1]:=a[i].x1;
X[i*2]:=a[i].x2;
Y[i*2-1]:=a[i].y1;
Y[i*2]:=a[i].y2;
end;
Sapxep(X); Sapxep(Y);
for i:=2 to 2*N do
for j:=2 to 2*N do
if Kiemtra_thuoc(i,j) then S:=s+(X[i]-X[i-1])*(Y[j]-Y[j-1]);
end;
{====================================}
Begin
doc_dl;
s:=0;
Xuly;
Write('Dien tich la: ', S);
readln;

End.
VD
2
. Phủ S
Trên mặt phẳng tọa độ, một hình chữ nhật với các cạnh song song với các
trục toạ độ được xác định bởi hai điểm đối tâm: đỉnh góc trên bên trái và đỉnh góc
dưới bên phải. Cho N hình chữ nhật song song với các trục toạ độ. Phủ S của các
hình chữ nhật có diện tích nhỏ nhất chứa N hình chữ nhật đã cho.
Dữ liệu vào: Đọc từ tệp PHUCN.INP có cấu trúc:
- Dòng đầu tiên chứa N (N ≤30);
- Trong N dòng tiếp theo, mỗi dòng ghi 4 số là toạ độ của hai đỉnh đối tâm
của một hình chữ nhật, các số này là các số nguyên có trị tuyệt đối không quá 100.
Kết quả: Ghi ra tệp văn bản PHUCN.OUT
- Dòng 1 ghi toạ độ hai đỉnh đối tâm của phủ S các hình chữ nhật
- Dòng 2 ghi diện tích của phần hình S không nằm trong hình chữ nhật nào
trong N hình đã cho
• Ý tưởng:
- Xác định hình chữ nhật H nhỏ nhất bao tất cả các hình chữ nhật ban đầu:
Gọi minx,maxx lần lượt là hoành độ nhỏ nhất và lớn nhất trong các hoành độ
các đỉnh hình chữ nhật đã cho; miny, maxy lần lượt là tung độ nhỏ nhất và lớn nhất
trong các tung độ các đỉnh hình chữ nhật đã cho. Khi đó hình H có toạ độ đỉnh dưới
trái là (minx,miny) và đỉnh trên phải là (max,maxy). Đó là phủ S cần tìm.
- Tính diện tích hình H là (maxx-minx)(maxy-miny)
- Tính diện tích s phủ bởi các hình chữ nhật (đã nêu rõ ở phương pháp
chung)
PhuCN.INP PhuCN.OUT
3
10 30 40 10
20 20 60 0
0 40 30 0

0 40 60 0
500
14
- Phần diện tích cần tìm là: s1:=abs((maxx-minx)*(maxy-miny))-s
• Chương trình:
const maxn=1000;
Type Toa_do=record x1,y1,x2,y2:integer; end;
mang=array[1 2*maxn] of integer;
var N, s,s1,maxx,minx,maxy,miny:integer;
a:array[1 maxn] of toa_do;
x,y:mang;f:text;
{================Doc DL===============}
Procedure DocDL;
var f:text; i:integer;
begin
Assign(f,'HCN.Inp'); reset(f);
readln(f,n);
minx:=maxint; maxx:=-maxint; miny:=maxint; maxy:=-maxint;
for i:=1 to n do
begin
readln(f,a[i].x1,a[i].y1,a[i].x2,a[i].y2);
if a[i].x1<minx then minx:=a[i].x1;
if a[i].x2<minx then minx:=a[i].x2;
if a[i].y1<miny then miny:=a[i].y1;
if a[i].y2<miny then miny:=a[i].y2;
if a[i].x1>maxx then maxx:=a[i].x1;
if a[i].x2>maxx then maxx:=a[i].x2;
if a[i].y1>maxy then maxy:=a[i].y1;
if a[i].y2>maxy then maxy:=a[i].y2;
end;

close(f);
end;
{=================Sap xep mang tang dan=========}
Procedure sapxep(var t:mang);
var i,j,TG,m:integer;
begin
m:=2*n;
for i:=1 to m-1 do
for j:=i+1 to m do
if T[i]>T[j] then
begin
TG:=t[i];
T[i]:=T[j];
T[j]:=TG;
end;
end;
{========Kiem tra HCN moi thuoc HCN da cho===========}
function Kiemtra_Thuoc(i,j:integer):boolean;
var k:integer;
begin
kiemtra_thuoc:=true;
for k:=1 to n do
if (a[k].x1<=x[i-1]) and (x[i]<=a[k].x2)
and (a[k].y1<=y[j-1]) and (y[j]<=a[k].y2) then exit;
kiemtra_thuoc:=false;
end;
{=========Xu ly bai toan===========}
Procedure Xuly;
var i,j:integer;
begin

for i:=1 to n do
begin
X[i*2-1]:=a[i].x1;
X[2*i]:=a[i].x2;
Y[i*2-1]:=a[i].y1;
Y[2*i]:=a[i].y2;
end;
sapxep(X); sapxep(Y);
for i:=2 to 2*n do
15
for j:=2 to 2*n do
if kiemtra_thuoc(i,j) then s:=s+(x[i]-x[i-1])*(y[j]-y[j-1]);
writeln(s);
end;
{=========================================}
begin
s:=0;
docdl;
xuly;
assign(f,'HCN.out'); rewrite(f);
writeln(f,minx,' ',maxy,' ',maxx,' ',miny);
writeln(f,s);
s1:=abs(maxx-minx)*(maxy-miny)-s;
writeln(f,s1);
close(f);
end.
VD
3
. Diện tích phủ bởi các hình tròn
Trên mặt phẳng cho N hình tròn. Tính diện tích phần mặt phẳng bị phủ bởi

các hình tròn trên.
Dữ liệu: Cho trong file INP.BL3 dòng đầu là số lượng hình tròn, từ dòng thứ
2 trở đi mỗi dòng chứa 3 số nguyên dương là tọa độ x, y của tâm và bán kính của
từng hình tròn (các số trên cùng một dòng ghi cách nhau ít nhất 1 dấu cách)
Kết quả: Xuất ra màn hình
• Ý tưởng:
- Tìm hình chữ nhật nhỏ nhất có các cạnh song song với các trục toạ độ và chứa
toàn bộ N hình tròn
- Chia hình chữ nhật này thành lưới các ô vuông có cạnh 0.1 đơn vị, với mỗi ô
thuộc hình chữ nhật kiểm tra xem ô này có thuộc vào hình tròn nào đó hay không,
nếu có thì tăng diện tích cần tính lên 0.01 đơn vị.
• Chương trình
program Hinh_tron;
type DT=record x,y,r:longint end;
var a:array[1 100] of DT; s:real;
N,i,j,k,i1,j1,x1,y1,x2,y2:longint;
{==========================}
procedure nhap;
var f:text;
begin
assign(f,'Hinhtron.inp'); reset(f);
readln(f,n);
fillchar(a,sizeof(a),0);
for i:=1 to n do readln(f,a[i].x,a[i].y,a[i].r);
close(f);
end;
{==========================}
function kiemtra(x,y:real):boolean;
begin
kiemtra:=true;

for k:=1 to n do
if(sqr(x-a[k].x) +sqr(y-a[k].y)<=sqr(a[k].r)) then exit;
kiemtra:=false;
end;
{==========================}
procedure tinh;
begin
INP.BL3 KÕt qu¶:
3
0 0 5
1 1 5
7 0 1
Dien tich: 95.60
16
s:=0.0;
x1:=+maxint; y1:=x1; x2:=-maxint; y2:=x2;
for i:=1 to n do
with a[i] do
begin
if x1<x1+r then x1:=x-r;
if y1<y1+r then y1:=y-r;
if x2<x+r then x2:=x+r;
if y2<y+r then y2:=y+r;
end;
for i:=x1 to x2 do
for i1:=0 to 9 do
for j:=y1 to y2 do
for j1:=0 to 9 do
if kiemtra(i+i1*0.1,j+j1*0.1) then s:=s+0.01;
writeln('dien tich:',s:0:2);

end;
{===========================}
begin
nhap;
tinh;
readln;
end.
Dạng 4. Xác định đa giác nhỏ nhất bao tất cả các điểm, đa giác đã cho
Phương pháp: Cho N điểm A
1
, A
2
, , A
N
trên mặt phẳng. Để xác định một đa
giác không tự cắt chứa một số điểm đã cho và bao tất cả các điểm còn lại ta làm
như sau:
Bước 1. Tìm điểm có tung độ nhỏ nhất. Điểm đó sẽ là đỉnh đa giác
Bước 2. Giả sử ta đã chọn được điểm P
M
. Tìm điểm P
i
sao cho góc hợp bởi
P
M
P
i
và trục hoành là nhỏ nhất và đồng thời góc này phải lớn hơn góc hợp bởi P
M
P

M-
1
và trục hoành. Điểm P
i
sẽ là một đỉnh của đa giác.
Bước 3. Lấy kết quả là dãy các đỉnh P tìm được.
Lưu ý: Với bài toán tìm đa giác bao nhau thì cần ghi nhớ đa giác a bao đa
giác b khi mọi điểm trong đa giác b đều nằm trong đa giác a.
VD
1
. Đa giác không tự cắt
Cho N điểm A
1
, A
2
, , A
N
trên mặt phẳng. Các điểm đều có toạ độ nguyên
và không có 3 điểm bất kỳ trong chúng thẳng hàng. Hãy viết chương trình thực
hiện các công việc sau đây: Xác định một đa giác không tự cắt có đỉnh là một số
điểm trong các điểm đã cho và chứa tất cả các điểm còn
lại và có chu vi nhỏ nhất. Hãy tính diện tích đa giác này.
Dữ liệu: cho trong tệp HCN.INP gồm n+1 dòng
+ Dòng 1: Chứa số N
+ Dòng i+1 (1≤ i ≤ N): Ghi 2 chữ số nguyên x
i
,y
i
là toạ độ đỉnh A
i

.
Các số trên cùng một dòng cách nhau một khoảng trắng.
Kết quả: Xuất ra tệp HCN.Out
+ Dòng 1: Ghi 3 số K, V, S với K là số đỉnh đa giác tìm được, V là chu vi, S
là diện tích của nó.
HCN.inp HCN.out
5
0 1
4 4
0 4
4 0
2 2
4 15.12 14.00
4 4
0 4
0 1
4 0
17
+ Dòng i+1(1≤ i ≤ K): Ghi toạ độ của đỉnh đa giác.
• Ý tưởng:
- Tìm điểm có tung độ nhỏ nhất. Điểm đó sẽ là đỉnh đa giác
- Giả sử ta đã chọn được điểm P
M
. Tìm điểm P
i
sao cho góc hợp bởi P
M
P
i


trục hoành là nhỏ nhất và đồng thời góc này phải lớn hơn góc hợp bởi P
M
P
M-1

trục hoành. Điểm P
i
sẽ là một đỉnh của đa giác.
program dagiac;
type diem=record x,y:integer; end;
var n,i,m:integer;
DG:array[1 100] of diem;
L:array[1 100] of byte;
{============================}
procedure docDL;
var f:text;
begin
assign(f,'bai1.inp');
reset(f);
readln(f,n);
for i:=1 to n do readln(f,DG[i].x,DG[i].y);
close(f);
end;
{============================}
function Goc(p1,p2:diem):real;
var dx,dy,ax,ay:integer; t:real;
begin
dx:=p2.x-p1.x; ax:=abs(dx);
dy:=p2.y-p1.y; ay:=abs(dy);
if (dx=0) and (dy=0) then t:=0 else t:=dy/(ax+ay);

if dx<0 then t:=2-t else if dy<0 then t:=4+t;
Goc:=90*t;
end;
{============================}
function Thuchien:integer;
var min,m:integer; minangle,v:real; t:diem;
begin
min:=1;
for i:=2 to n do
if DG[i].y <DG[min].y then min:=i;
m:=0; DG[n+1]:=DG[min]; minangle:=0.0;
repeat
m:=m+1; t:=DG[m]; DG[m]:=DG[min]; DG[min]:=t;
min:=n+1; v:=minangle; minangle:=360.0;
for i:=m+1 to n+1 do
if goc(DG[m],DG[i])>v then
if goc(DG[m],DG[i])<minangle then
begin
min:=i;
minangle:= goc(DG[m],DG[min]);
L[m]:=i;
end;
until min=n+1;
thuchien:=m;
end;
{===========================}
procedure xuat;
var f:text; v,s:real;
begin
assign(f,'bai1.out');

rewrite(f);
write(f,thuchien,' ');
L[m+1]:=L[1];
V:=0;
DG[L[n+1]].x:=DG[L[1]].x;
DG[L[n+1]].y:=DG[L[1]].y;
18
for i:=1 to m do v:=v+sqrt(sqr(DG[L[i]].x-DG[L[i+1]].x) + sqr(DG[L[i]].y-
DG[L[i+1]].y));
S:=0;
for i:=1 to m do
s:=s+(DG[L[i+1]].x-DG[L[i]].x)*(DG[L[i+1]].y+DG[L[i]].y)/2;
S:=abs(s);
writeln(f,V:0:2,' ',S:0:2);
For i:=1 to m do writeln(f,DG[L[i]].x,' ',DG[L[i]].y);
close(f);
end;
{=========================}
Begin
docDL;
xuat;
End.
VD
2
. Đa giác bao nhau
Cho N đa giác thoả mãn các tính chất
- Với 2 đa giác bất kỳ luôn có một đa giác mà mọi điểm của nó nằm trong đa
giác kia.
- Các cạnh của chúng không có điểm chung.
Bài toán đặt ra là: Với mỗi đa giác i, có bao nhiêu đa giác bao nó? (i nằm

trong bao nhiêu đa giác)
Dữ liệu vào: Ghi trong tập tin văn bản Dagiac.Inp.
- Dòng đầu tiên ghi số tự nhiên N (3=N=10000).
- Trên N dòng tiếp theo: Dòng thứ i+1 ghi thông tin về đa giác có số hiệu thứ
i. Bao gồm số đầu tiên S
i
là số đỉnh của đa giác (S
i
=3), S
i
cặp số nguyên tiếp theo
lần lượt là hoành độ và tung độ các đỉnh của đa giác.
Các số trên cùng dòng cách nhau bởi ít nhất một khoảng trắng.
Dữ liệu ra: Ghi trong tập tin Dagiac.Out
- Gồm N dòng
- Dòng thứ i: Ghi số lượng đa giác bao đa giác i.
• Ý tưởng:
- Sử dụng các mảng a,vt,kq (với a[i] lưu giá trị hoành độ nhỏ nhất của các
đỉnh của đa giác thứ i, vt[i] chỉ đa giác thứ i, mảng kq lưu kết quả)
- Thực hiện sắp xếp các đa giác theo thứ tự tăng dần của giá trị hoành độ nhỏ
nhất của các đỉnh của các đa giác.
- Do theo điều kiện bài toán là với 2 đa giác bất kỳ luôn có một đa giác mà
mọi điểm của nó nằm trong đa giác kia nên KQ[vt[i]] =i-1
• Chương trình:
Program dagiac;
var a,vt,kq: array[1 1000] of integer;
n,i:integer; fi,fo:text;
{=========================}
procedure doc_dl;
var i,j,min,k,x,y:integer;

begin
assign(fi,'dagiac.inp'); reset(fi);
readln(fi,n);
for i:=1 to n do
begin
read(fi,k); min:=maxint;
Dagiac.INP Dagiac.OUT
4
4 1 1 15 1 15 8 1 8
4 9 3 9 6 4 6 4 3
4 3 2 11 2 11 7 3 7
3 8 4 8 5 6 5
0
2
1
3
19
for j:=1 to k do
begin read(fi,x,y); if x<min then min:=x; end;
a[i]:=min;
vt[i]:=i;
end;
end;
{===========================}
procedure sapxep(l,r:integer);
var i,j,mid,tg:integer;
begin
i:=l; j:=r; mid:=a[(l+r) div 2];
repeat
while a[i]<mid do inc(i);

while mid<a[j] do dec(j);
if i<=j then
begin
tg:=a[i]; a[i]:=a[j]; a[j]:=tg;
tg:=vt[i]; vt[i]:=vt[j]; vt[j]:=tg;
i:=i+1; j:=j-1;
end;
until i>j;
if l<j then sapxep(l,j);
if i<r then sapxep(i,r);
end;
{===============================}
begin
doc_dl;
sapxep(1,n);
assign(fo,'Dagiac.out'); rewrite(fo);
for i:=1 to n do kq[vt[i]]:=i-1;
for i:=1 to n do writeln(fo,kq[i]);
close(fi); close(fo);
end.
VD
3
.Hình chữ nhật bao nhau
Cho N hình chữ nhật trên mặt phẳng mà các cạnh
song song với các trục toạ độ. Biết hình chữ nhật i bao
hình chữ nhật j nếu cả 4 đỉnh của hình chữ nhật j đều
nằm trong hình chữ nhật i hoặc nằm trên cạnh của hình
chữ nhật i.
Một dãy các hình chữ nhật được gọi là hình chữ nhật bao nhau chiều dài k
(k≥1) nếu dãy này gồm các hình chữ nhật H1, H2, , Hk sao cho hình chữ nhật i

bao hình chữ nhật i+1 với i=1 (k-1). Hãy tìm số k lớn nhất nói trên.
Dữ liệu vào: Được cho trong tập tin HCN.INP
- Dòng thứ nhất ghi số N (1=N=1000).
- N dòng tiếp theo, dòng thứ i ghi 4 số nguyên x1, y1, x2, y2 (-10000<
x1,y1,x2,y2<10000) lần lượt là hoành độ, tung độ các đỉnh trái trên, phải dưới của
hình chữ nhật.
Kết quả: Được ghi vào tệp văn bản HCN.OUT gồm một dòng chứa số nguyên
duy nhất là số k tìm được hoặc số -1 nếu không tồn tại số k thoả điều kiện đề bài.
• Ý tưởng:
- Tính diện tích các hình chữ nhật (HCN)
- Sắp xếp lại các HCN theo thứ tự không giảm của diện tích các HCN
- Lập hàm kiểm tra HCN i bao HCN j, thoả mãn điều kiện:
(x1[i]<=x1[j]) and (y1[i]>=y1[j]) and (x2[i]>=x2[j]) and (y2[i]<=y2[j])
HCN.INP HCN.OUT
6
1 5 2 2
2 4 3 3
1 5 5 2
4 3 8 1
5 6 8 4
6 6 8 5
2
20
- Xác định số lượng các HCN bao HCN i và lưu vào phần tử mảng kq[i] biết
rằng: nếu <HCN i bao HCN j > thì kq[i]:=kq[j]+1
•Ch¬ng tr×nh:
Var x1,y1,x2,y2,kq:array[1 1000] of integer;
n: integer; fi,fo:text;
{===============================}
Procedure Doc_DL;

Var i:integer;
Begin
Assign(fi,'HCN.inp'); reset(fi);
readln(fi,n);
for i:=1 to n do read(fi,x1[i],y1[i],x2[i],y2[i]);
close(fi);
end;
{==================================}
Function DT_HCN(i:integer):longint;
Begin
DT_HCN:=longint(abs(x1[i]-x2[i]))*longint(abs(y1[i]-y2[i]));
end;
{=============================}
Procedure Qsort(l,r:integer);
Var i,j,mid,t:integer;
Begin
mid:=(l+r) div 2;
i:=l; j:=r;
Repeat
while DT_HCN(i)<DT_HCN(mid) do inc(i);
while DT_HCN(j)>DT_HCN(mid) do dec(j);
if i<=j then
begin
t:=x1[i]; x1[i]:=x1[j]; x1[j]:=t;
t:=x2[i]; x2[i]:=x2[j]; x2[j]:=t;
t:=y1[i]; y1[i]:=y1[j]; y1[j]:=t;
t:=y2[i]; y2[i]:=y2[j]; y2[j]:=t;
end;
until i>j;
if i<r then qsort(i,r);

if j>l then qsort(l,j);
end;
{===============================}
function Bao(i,j:integer):integer;
Begin
if (x1[i]<=x1[j]) and (y1[i]>=y1[j]) and (x2[i]>=x2[j])
and (y2[i]<=y2[j]) then bao:=1 else bao:=0;
end;
{==================================}
Procedure Xuly;
Var i,j:integer;
Begin
for i:=1 to n do kq[i]:=1;
for i:=2 to n do
for j:=1 to i-1 do
if bao(i,j)=1 then kq[i]:=kq[j]+1;
end;
{=================================}
BEGIN
doc_DL;
qsort(1,n);
xuly;
tmp:=0;
for i:=1 to n do
if kq[i]>tmp then tmp:=kq[i];
if tmp=1 then tmp:=-1;
assign(fo,'HCN.out'); rewrite(fo);
writeln(fo,tmp);
close(fo);
21

END.
VD
4
. Hình chữ nhật bao nhau
Hình chữ nhật A bao hình chữ nhật B nếu mọi điểm thuộc hình chữ nhật B
đều nằm trong hoặc thuộc hình chữ nhật A.
Trong mặt phẳng Oxy cho n hình chữ nhật có các cạch song song với các
trục toạ độ. Yêu cầu:
1. Tìm số hình chữ nhật bao nhau nhiều nhất (số lượng hình phải >1).
2. Trong số các tập hình chữ nhật bao nhau, tìm tập các hình chữ nhật bao
nhau có tổng diện các diện tích của các hình chữ nhật trong tập là lớn nhất.
3. Tìm hiệu diện tích của hình chữ nhật nhỏ nhất bao tất cả các hình chữ nhật
đã cho với diện tích của phần mặt phẳng bị phủ bởi các hình chữ nhật đã cho.
Dữ liệu vào: Cho trong tệp văn bản HCN.IN
- Dòng đầu: n (số lượng hình chữ nhật, 1=N=1000)
- n dòng tiếp theo: Mỗi dòng chứa 4 số dạng a, b, c, d (a, b, c, d là các số
nguyên) với (a, b) và (c, d) là toạ độ của hai đỉnh đối tâm của hình chữ nhật.
Kết quả: Xuất ra tệp văn bản HCN.Out
- Dòng đầu: Cho biết tập các hình chữ nhật bao nhau nhiều nhất theo dạng k l
m n với ý nghĩa-Hình chữ nhật thứ k thuộc hình chữ nhật thứ l, hình chữ nhật thứ
l thuộc hình chữ nhật thứ m, hình chữ nhật thứ m thuộc hình chữ nhật n nếu
không có thì ghi từ "khong"
- Dòng thứ 2: Cho biết tập các hình chữ nhật bao nhau có tổng các diện tích
của các hình chữ nhật trong tập hợp là lớn nhất theo qui cách như dòng thứ nhất.
Nếu không thì ghi số 0.
- Dòng thứ 3: Chứa con số biểu diễn hiệu diện tích hình chữ nhật nhỏ nhất
bao tất cả hình chữ nhật đã cho với diện tích của phần mặt phẳng bị phủ bởi các
hình chữ nhật đã cho.
• Ý tưởng:
- Lưu tọa độ các đỉnh hình chữ nhật vào 4 mảng x1,y1,x2,y2

- Dùng mảng bao(n,n) để đánh dấu các hình chữ nhật bao nhau: Với
bao[i,j]=1 có nghĩa hình chữ nhật i bao hình chữ nhật j, bao[i,j]=0 thì ngược lại.
- Dãy hình chữ nhật thứ i, k, j gọi là bao nhau nếu (Bao[i,k]
+bao[k,j]>bao[i,j]) và (bao[i,k]>0) và (bao[k,j]>0). Sử dụng mảng KQ để lưu các
hình chữ nhật k thoả mãn
- Hình chữ nhật nhỏ nhất bao tất cả các hình chữ nhật đã cho là hình chữ nhật
có toạ độ góc dưới phải là (x
min
,y
min
) và toạ độ góc trên trái là (x
max
,y
max
)
- Phương pháp tìm diện tích phủ đã trình bày ở dạng 3
Chương trình
const maxn=100;
Type Toa_do=record x1,y1,x2,y2:integer; end;
mang=array[1 2*maxn] of integer;
mang1=array[1 maxn,1 maxn] of integer;
var a:array[1 maxn] of toa_do;
x,y:mang; f,f1:text;
minx,miny,maxx,maxy,n:integer;
HCN.IN HCN.OUT
3
0 0 4 4
5 0 6 4
0 0 2 2
1 3

1 3
4
22
x1,y1,x2,y2:array[1 maxn] of integer;
kq:array[1 maxn,1 maxn] of byte;
s,bao:mang1;
{========================ar=========}
function min(a,b:integer):integer;
begin
if a>b then min:=b else min:=a;
end;
{================================}
function max(a,b:integer):integer;
begin
if a>b then max:=a else max:=b;
end;
{==================================}
procedure DocDL;
var i:integer;
Begin
assign(f,'HCN.IN'); reset(f);
readln(f,n);
for i:=1 to n do
begin
read(f,x1[i],y1[i],x2[i],y2[i]);
a[i].x1:=x1[i];a[i].y1:=y1[i];a[i].x2:=x2[i];a[i].y2:=y2[i];
if a[i].x1<minx then minx:=a[i].x1;
if a[i].x2<minx then minx:=a[i].x2;
if a[i].y1<miny then miny:=a[i].y1;
if a[i].y2<miny then miny:=a[i].y2;

if a[i].x1>maxx then maxx:=a[i].x1;
if a[i].x2>maxx then maxx:=a[i].x2;
if a[i].y1>maxy then maxy:=a[i].y1;
if a[i].y2>maxy then maxy:=a[i].y2;
end;
close(f);
end;
{========================================}
procedure Xuat(x,y:integer);
begin
if kq[x,y]=0 then write(f1,x,' ')
else xuat(x,kq[x,y]);
write(f1,y,' ');
end;
{=================================}
function DT(i:integer):integer;
begin
dt:=abs(x1[i]-x2[i])*abs(y1[i]-y2[i]);
end;
{=========================================}
function ktra_bao(i,j:integer):boolean;
begin
ktra_bao:=false;
if (min(x1[j],x2[j])>=min(x1[i],x2[i])) and
(min(y1[j],y2[j])>=min(y1[i],y2[i])) and
(max(x1[j],x2[j])<=max(x1[i],x2[i])) and
(max(y1[j],y2[j])<=max(y1[i],y2[i])) then ktra_bao:=true;
end;
{========================================}
procedure khoi_tao;

var i,j:integer;
Begin
for i:=1 to n do
for j:=1 to n do
if i<>j then
if ktra_bao(i,j) then Bao[i,j]:=1;
end;
{========================================}
procedure cau_a;
var i,j,k,io,jo:integer; fg:boolean;
23
begin
for i:=1 to n do
for j:=1 to n do
if i<>j then
for k:=1 to n do
if (i<>k) and (j<>k) and (Bao[i,k]+bao[k,j]>bao[i,j]) and
(bao[i,k]>0) and (bao[k,j]>0) then
begin
bao[i,j]:=bao[i,k]+bao[k,j];
kq[i,j]:=k;
end;
io:=1; jo:=2; fg:=true;
for i:=1 to n do
for j:=1 to n do
if bao[i,j]>bao[io,jo] then
begin io:=i; jo:=j; fg:=true; end
else if bao[i,j]=bao[io,jo] then fg:=false;
assign(f1,'HCN.out'); rewrite(f1);
if (bao[io,jo]>=1) and (fg=true) then xuat(io,jo)

else write(f1,'Khong');
end;
{====================================}
procedure cau_b;
var i,j,k,io,jo:integer; fg:boolean;
begin
writeln(f1);
fillchar(kq,sizeof(kq),0);
for i:=1 to n do
for j:=1 to n do
if (i<>j) and ktra_bao(i,j) then s[i,j]:=dt(i) + dt(j);
for i:=1 to n do
for j:=1 to n do
if i<>j then
for k:=1 to n do
if (i<>k) and (j<>k) and (s[i,k]+s[k,j]>s[i,j])
and (s[i,k]>0) and (s[k,j]>0) then
begin
s[i,j]:=s[i,k]+s[k,j];
kq[i,j]:=k;
end;
io:=1; jo:=2; fg:=true;
for i:=1 to n do
for j:=1 to n do
if (i<>j) and (s[i,j]>s[io,jo]) then
begin io:=i; jo:=j; fg:=true; end
else if s[i,j]=s[io,jo] then fg:=false;
if s[io,jo]>0 then xuat(io,jo) else writeln(f1,0);
end;
{====================================}

procedure cau_c;
var s1,i,j:integer;
{=================Sap xep mang tang dan=========}
Procedure sapxep(var t:mang);
var i,j,TG,m:integer;
begin
m:=2*n;
for i:=1 to m-1 do
for j:=i+1 to m do
if T[i]>T[j] then
begin
TG:=t[i];
T[i]:=T[j];
T[j]:=TG;
24
end;
end;
{========Kiem tra HCN moi thuoc HCN da cho===========}
function Kiemtra_Thuoc(i,j:integer):boolean;
var k:integer;
begin
kiemtra_thuoc:=true;
for k:=1 to n do
if (a[k].x1<=x[i-1]) and (x[i]<=a[k].x2)
and (a[k].y1<=y[j-1]) and (y[j]<=a[k].y2) then exit;
kiemtra_thuoc:=false;
end;
{*********************}
begin
s1:=0; docdl;

for i:=1 to n do
begin
X[i*2-1]:=a[i].x1;
X[2*i]:=a[i].x2;
Y[i*2-1]:=a[i].y1;
Y[2*i]:=a[i].y2;
end;
sapxep(X); sapxep(Y);
for i:=2 to 2*n do
for j:=2 to 2*n do
if kiemtra_thuoc(i,j) then s1:=s1+(x[i]-x[i-1])*(y[j]-y[j-1]);
writeln(f1);
writeln(f1,abs((maxx-minx)*(maxy-miny))-s1);
end;
{====================================}
begin
docDL;
khoi_tao;
cau_a;
cau_b;
cau_c;
close(f1);
end.
IV. BÀI TẬP ÁP DỤNG
Bài 1. Lớp đoạn thẳng
Cho tập n đoạn thẳng đánh số từ 1 n với các mút toạ độ là các số thực
(Li,Ri), i:1 n trong đó Li, Ri lần lượt là các đầu mút bên trái và bên phải của đoạn
thẳng thứ i.
Đoạn thẳng thứ i gọi là nằm trong đoạn thẳng thứ j nếu mọi điểm thuộc đoạn
thẳng i đều thuộc đoạn thẳng j.

Người ta phân đoạn thẳng này thành từng lớp: Lớp của các đoạn thẳng là một
tập hợp chứa các đoạn thẳng không nằm trong nhau.
Hãy phân lớp các đoạn thẳng trên sao cho số lớp là ít nhất.
Dữ liệu vào: DL.INP
- Dòng 1: Số n (n<=200)
- Dòng i+1 gồm 2 số nguyên lần lượt là Li, Ri.
Dữ liệu ra: KQ.Out
DL.INP KQ.OUT
4
1 4
2 6
2 4
5 8
2
3 1 2 4
1 3
25

×