Thứ Hai, 16 tháng 12, 2013

Các hình chữ nhật



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 £ x2y1 £ 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
LẬP TRÌNH


Không có nhận xét nào:

Đăng nhận xét