Trên mặt phẳng tọa độ cho N hình chữ nhật (HCN) có diện tích khác 0
và có các cạnh song song với các trục tọa độ. Mỗi HCN được mô tả bằng bộ bốn số
nguyên (x1,y1) và (x2,y2) biểu thị tọa
độ nguyên của hai đỉnh đối diện.
Yêu cầu: xác định diện tích phần mặt phẳng bị các HCN phủ.
HCN.INP
|
HCN.OUT
|
|
Dữ
liệu vào: tệp văn bản HCN.INP
Dòng
đầu tiên: số tự nhiên 1 < N £ 1000.
Dòng
thứ i trong N dòng tiếp theo, mỗi dòng chứa 4 số nguyên x1, y1,
x2, y2 cách nhau qua dấu cách.
Dữ
liệu ra: tệp văn bản HCN.OUT
chứa tổng đơn vị diện tích trên mặt phẳng bị các HCN phủ.
|
5
0 0 2 4
1 2 4 6
5 3 3 7
4 1 6 5
7 3 9 0
|
35
|
|
Thuật toán
Phương pháp: Tham.
|
|
|
|
y2
|
A
|
|
B
|
|
|
|
|
|
|
|
|
y1
|
|
|
|
|
D
|
|
C
|
|
|
x1
|
x2
|
1. Đọc dữ liệu và chỉnh lại các tọa độ sao cho
x1 £ x2 và y1 £ y2. Điều này có nghĩa là ta qui ước mọi HCN ABCD đều được xác định qua 2 đỉnh đối diện D (đỉnh Tây-Nam) và B (đỉnh Đông-Bắc): D(x1, y1), B(x2, y2).
x1 £ x2 và y1 £ y2. Điều này có nghĩa là ta qui ước mọi HCN ABCD đều được xác định qua 2 đỉnh đối diện D (đỉnh Tây-Nam) và B (đỉnh Đông-Bắc): D(x1, y1), B(x2, y2).
Khi đọc dữ liệu ta đồng thời lược bớt các giá trị y trùng lặp và sắp các giá trị y1 và y2 theo
chiều tăng để ghi vào một mảng y[1..m]. Như vậy, giá trị lớn nhất của m là 2n. Ta gọi phần mặt phẳng giới hạn bởi hai đường thẳng song song với
trục hoành và cắt trục tung tại điểm y[i] và y[i+1] là băng i. Ta có m-1
băng mã số từ 1 đến m-1.
Băng đầu tiên có mã số 1 nằm giữa hai
đường y[1] và y[2], băng cuối cùng có mã số m-1 nằm giữa hai đường y[m-1] và y[m]. Nhiệm vụ còn lại là tính diện tích
bị phủ trên mỗi băng. Tổng số diện tích bị phủ của các băng sẽ là đáp số cho
bài toán.
2. Ta lại sắp các HCN theo chiều tăng của tọa độ x1.
3. Với mỗi HCN h(x1,
y1, x2, y2) ta xét các băng i trong khoảng từ y1 đến y2. Với băng i giả sử ta đã biết phần bị các HCN 1..(h-1) phủ trên băng này. Ta kí hiệu s[i]
và e[i] là giới hạn hoành độ trái và phải của phần đang bị phủ trên băng
i. Diện tích hiện bị phủ trên băng i sẽ là: (y[i+1]-y[i])*(e[i]
– s[i]), trong đó y[i+1] – y[i] là chiều rộng của
băng i. Ta cần chỉnh lại phần bị phủ
trong băng i khi xét thêm HCN h(x1,
y1, x2, y2). Dễ thấy, nếu x1 nằm giữa s[i] và e[i]
thì ta cần chỉnh lại e[i] theo công thức e[i] := max(e[i],
x2). Ngược lại, nếu x1 > e[i] thì ta kết thúc làn
(s[i],e[i]) này như sau: Tính diện tích làn này và đưa vào biến tích lũy
diện tích dt sau đó đặt lại cận s[i]
:= x1; e[i] := x2.
Do các hoành độ y1 và y2 được sắp tăng nên ta có
thể gọi thủ tục tìm kiếm nhị phân BínSearch để xác định băng chứa y1.
Độ phức tạp: Các thuật toán sắp xếp và chèn đòi hỏi tối đa N2, Thủ tục xử lí xét mỗi HCN 1 lần và duyệt 2n băng. Tổng hợp: N2.
(* Pascal *)
(**********************************************
Cac hinh chu
nhat
*********************************************)
program HinhChuNhat;
uses crt;
const mn = 2001; fn = 'HCN.INP'; gn = 'HCN.OUT';
bl = #32; nl =
#13#10;
type CN = record
x1, y1: integer;
x2, y2: integer;
end;
mcn1 = array[0..mn] of CN;
mi1 = array[0..mn] of integer;
var
n,m: integer; { n - so HCN,
m - so lan }
h: mcn1; { cac HCN }
y: mi1; { ranh gioi cac lan }
s, e: mi1; { Cac diem dau va cuoi cua bang }
f,g: text;
dt: Longint;
function Max(a,b: integer): tự viết
(*-----------------------------
Hoán đổi trị để a £ b
------------------------------*)
procedure Chinh(var a,b: integer);
var c: integer;
begin
if (a > b) then begin c := a; a := b; b := c; end;
end;
(*------------------------------------
Tim nhi phan v trong
y[1..m]
-------------------------------------*)
function BinSearch(v: integer): integer;
var d,c,t: integer;
begin
d := 1 ; c := m;
while (d < c) do
begin
t := (d + c) div 2;
if (y[t] < v) then
d := t + 1
else c := t;
end;
BinSearch := d;
end;
(*-----------------------------
Xen them v vao day
da sap tang y[1..m]
------------------------------*)
procedure Insert(v: integer);
var d: integer;
begin
if (m = 0) then { danh
sach rong }
begin m := m + 1; y[m] := v; exit; end;
d := BínSearch(v);
if (y[d] = v) then exit; { da co trong danh sach }
if (y[d] < v) then begin
m := m + 1; y[m] := v; exit; end;
move(y[d], y[d+1],sizeof(integer)*(m-d+1));
y[d] := v; m := m + 1;
end;
(*-------------------------------
Doc du lieu va sap theo Y
luoc bot cac Y bang nhau
------------------------------*)
procedure Doc;
var i: integer;
begin
assign(f,fn); reset(f);
readln(f,n); m := 0;
for i := 1 to n do
begin
readln(f,h[i].x1,h[i].y1,h[i].x2,h[i].y2);
Chinh(h[i].x1,
h[i].x2); Chinh(h[i].y1, h[i].y2);
insert(h[i].y1); insert(h[i].y2);
end;
close(f);
end;
procedure SortByX1(d,c: integer);
var i,j,m: integer;
v: CN;
begin
i := d; j := c;
m := h[(i+j) div 2].x1;
while (i <= j) do
begin
while (h[i].x1 < m) do
i := i + 1;
while (m < h[j].x1) do
j := j - 1;
if (i <= j) then
begin
v := h[i]; h[i] :=
h[j]; h[j] := v;
i := i + 1; j := j
- 1;
end;
end;
if (d < j) then
SortByX1(d,j);
if (i < c) then
SortByX1(i,c);
end;
(*----------------------------------
Xet HCN d, tinh tung
phan
phu trong moi lan
------------------------------------*)
procedure Hinh(x1, x2, y1, y2: integer);
var i: integer;
begin
{ Tim xuat hien cua y1 trong cac lan }
i := BinSearch(y1);
while (y[i] < y2) do
begin
if (x1 <= e[i]) then
e[i] := Max(e[i], x2)
else
begin
dt := dt + (e[i] - s[i])
* (y[i+1] - y[i]);
s[i] := x1; e[i] :=
x2;
end;
i := i + 1;
end;
end;
procedure XuLi;
var d: integer;
begin
{ Khoi tri }
dt := 0;
for d := 1 to m-1 do
begin s[d] := -maxint; e[d]
:= s[d]; end;
{ Duyet cac HCN }
for d := 1 to n do
Hinh(h[d].x1, h[d].x2, h[d].y1, h[d].y2);
{ Tong hop ket qua }
for d := 1 to m-1 do
dt
:= dt + (e[d] - s[d]) * (y[d+1] - y[d]);
end;
procedure Ghi;
begin
assign(g,gn); rewrite(g);
writeln(g,dt); close(g)
end;
BEGIN
Doc; SortByX1(1,n); XuLi; Ghi;
END.
Nguồn:
SÁNG TẠO
TRONG THUẬT TOÁN
VÀ
LẬP TRÌNH
Không có nhận xét nào:
Đăng nhận xét