Hotline: 024.62511017

024.62511081

  Trang chủ   Sản phẩm   Phần mềm Dành cho nhà trường   Phần mềm Hỗ trợ học tập   Kho phần mềm   Liên hệ   Đăng nhập | Đăng ký

Tìm kiếm

School@net
 
Xem bài viết theo các chủ đề hiện có
  • Hoạt động của công ty (726 bài viết)
  • Hỗ trợ khách hàng (498 bài viết)
  • Thông tin tuyển dụng (57 bài viết)
  • Thông tin khuyến mại (80 bài viết)
  • Sản phẩm mới (216 bài viết)
  • Dành cho Giáo viên (549 bài viết)
  • Lập trình Scratch (3 bài viết)
  • Mô hình & Giải pháp (156 bài viết)
  • IQB và mô hình Ngân hàng đề kiểm tra (127 bài viết)
  • TKB và bài toán xếp Thời khóa biểu (242 bài viết)
  • Học tiếng Việt (183 bài viết)
  • Download - Archive- Update (289 bài viết)
  • Các Website hữu ích (70 bài viết)
  • Cùng học (92 bài viết)
  • Learning Math: Tin học hỗ trợ học Toán trong nhà trường (78 bài viết)
  • School@net 15 năm (154 bài viết)
  • Mỗi ngày một phần mềm (7 bài viết)
  • Dành cho cha mẹ học sinh (124 bài viết)
  • Khám phá phần mềm (122 bài viết)
  • GeoMath: Giải pháp hỗ trợ học dạy môn Toán trong trường phổ thông (36 bài viết)
  • Phần mềm cho em (13 bài viết)
  • ĐỐ VUI - THƯ GIÃN (363 bài viết)
  • Các vấn đề giáo dục (1210 bài viết)
  • Bài học trực tuyến (1037 bài viết)
  • Hoàng Sa - Trường Sa (17 bài viết)
  • Vui học đường (275 bài viết)
  • Tin học và Toán học (220 bài viết)
  • Truyện cổ tích - Truyện thiếu nhi (180 bài viết)
  • Việt Nam - 4000 năm lịch sử (97 bài viết)
  • Xem toàn bộ bài viết (8223 bài viết)
  •  
    Đăng nhập/Đăng ký
    Bí danh
    Mật khẩu
    Mã kiểm traMã kiểm tra
    Lặp lại mã kiểm tra
    Ghi nhớ
     
    Quên mật khẩu | Đăng ký mới
     
    Thành viên có mặt
    Khách: 10
    Thành viên: 0
    Tổng cộng: 10
     
    Số người truy cập
    Hiện đã có 89674363 lượt người đến thăm trang Web của chúng tôi.

    Các cấu trúc dữ liệu đặc biệt - PIV: Range Minimum Query

    Ngày gửi bài: 22/10/2008
    Số lượt đọc: 3287

    Range Minimum Query [RMQ] là 1 dạng cấu trúc đặc biệt hiệu quả trong bài toán tìm min, max của nhiều đoạn liên tiếp khác nhau của 1 dãy số cho trước.

    Bài toán: Cho dãy số A gồm N số cho trước. Có 1 số câu hỏi dạng yêu cầu trả về giá trị min/max các phần tử thuộc dãy trong đoạn từ I tới J.

    Không mất tổng quát ta xét bài toán tìm min.

    Để giải quyết bài toán này ta có thể dùng interval tree với độ phức tạp cho mỗi yêu cầu là O(logN) và khởi tạo trong O(NlogN) nhưng 1 cách tốt hơn là dùng RMQ.

    Ở đây xin đề cập tới phương pháp dùng RMQ với độ phức tạp O(NlogN) để khởi tạo và O(1) để trả lời 1 yêu cầu. Ngoài ra, cũng có 1 cách khác dùng RMQ với độ phức tạp để khởi tạo chỉ còn là O(N) nhưng khá tốn bộ nhớ và rất phức tạp.

    Tư tưởng thuật toán là chia để trị. Ta cần 1 mảng RMQ với bộ nhớ O(NlogN) như sau: với mỗi i,j: R[i,j] là giá trị min trong đoạn từ i tới i+2^j-1 (1<=i<=N, 1<=j<=logN, i+2^j-1<=N). Tức là từ 1 vị trí i bất kì ta tính trước min các đoạn có độ dài là luỹ thừa của 2. Giả sử đã có mảng R, ta dễ dàng tìm giá trị min trong đoạn từ U tới V bằng cách KQ:=min(R[u,k],R[v-2^k+1,k]) trong đó k là GTLN thoả mãn 2^k<=V-U+1.

    Có thể thấy đoạn [u..v] đã bị phủ bởi 2 đoạn nhỏ [u..u+2^k-1] và [v-2^k+1..v] vì tổng độ dài 2 đoạn đó là 2^k+1>v-u+1 mà 2 đoạn này chỉ gồm các phần tử thuộc trong đoạn [u..v]. Vậy giá trị KQ tìm được ở trên chính là min(u,v).

    Vấn đề còn lại là khởi tạo mảng R trong O(NlogN) như thế nào? từ công thức tìm min trên ta có thể dễ dàng suy ra cách khởi tạo mảng R: R[i,j]=min(R[i,j-1],R[i+2^j,j-1]

    Đây là thủ tục khởi tạo mảng R:

    Procedure khoitao;

    Var i,j,k:longint;

    Begin

    For i:=1 to N do R[i,0]:=A[i]; {với j=1}

    K:=trunc(ln(N)/ln(2));{ln(N)/ln(2)=log(N)}

    For j:=1 to k do

    For i:=1 to n-1 shl j+1 do {1 shl j=2^j}

    If R[i,j-1]

    End;

    Và để tìm min đoạn từ vị trí i tới vị trí j ta dùng Function FindMin sau:

    Function Findmin(i,j:longint):longint;

    Var k:longint;

    Begin

    K:=trunc(ln(j-i+1)/ln(2));

    If R[i,k]

    else FindMin:=R[j-1 shl k+1,k];

    End;

    RMQ là 1 cách tiếp cận thông minh bài toán trên. Nhưng ứng dụng của RMQ không lớn và đa dạng bằng các cấu trúc khác, cách sử dụng RMQ chủ yếu là đưa bài toán trở về bài toán trên và giải bằng RMQ. Nhưng tư tưởng chia để trị như của RMQ thì có ứng dụng trong khá nhiều bài toán khác.

    Sau đây là 1 ví dụ về ứng dụng của RMQ: trong bài toán tìm LCA (least common ancestor) - tổ tiên chung gần nhất của 2 nút U,V trên 1 cây cho trước. Với 2 nút U,V thì LCA(u,v) là nút cao nhất mà là tổ tiên của cả u và v.

    Bài toán: cho 1 cây gồm N nút. Có 1 số yêu cầu trả về nút là tổ tiên chung gần nhất của cặp nút U,V.

    Phương pháp giải:

    Gọi mảng H[i] là độ cao của nút I, hay nói cách khác là độ dài đường đi từ gốc tới nút I. Đầu tiên cần chuyển bài toán tìm LCA về bài toán đã nêu. Nhận xét: trên đường đi từ U tới V thì nút có độ cao nhỏ nhất chính là cha chung của U và V.

    Xét mảng B được xây dựng như sau:

    Procedure ktB(i:longint);

    Begin

    Inc(m);B[m]:=i;C[i]:=m;

    For j {thuộc tập con của i} do ktB(j);

    If cha[i]<>0 then begin Inc(m);B[m]:=cha[i];end;

    End;

    M là số phần tử của mảng B, khởi tạo m:=0;

    Mảng B gọi là 1 Euler tour trên cây đã cho, xây dựng bằng cách DFS từ gốc, đi qua 1 nút thì thêm nút đó vào trong mảng B. Độ phức tạp khởi tạo mảng B bằng độ phức tạp của thuật toán DFS tức là O(N) đối với cây nếu dùng danh sách liên kết động. Số phần tử của B là m=2*n. Mảng C lưu lại vị trí của I trong mảng B. Nhận xét thấy giá trị LCA(u,v) chính là nút, hay phần tử của B trong đoạn từ C[u] tới C[v] có độ cao đạt min. Nếu như vậy dựa vào mảng B,H và dùng RMQ dễ dàng xác định được LCA(u,v). Cài đặt RMQ trong trường hợp này khác 1 chút ở điểm giá trị so sánh là H[] chứ không phải là B[], rất dễ nhầm lẫn trong cài đặt. Giả sử đã có mảng B[],C[] và H như mô tả, sau đây là code thể hiện thuật toán tìm LCA dựa vào RMQ.

    Procedure khoitaoR;

    Var i,j,k:longint;

    Begin

    For i:=1 to M do R[i,0]:=B[i]; {với j=1}

    K:=trunc(ln(M)/ln(2));

    For j:=1 to k do

    For i:=1 to M-1 shl j+1 do

    If H[R[i,j-1]]

    else R[i,j]:=R[i+1 shl j,j-1];

    End;

    Function LCA(i,j:longint):longint;

    var i,j,k,tg:longint;

    Begin

    I:=C[i];J:=C[j];

    If i>j then

    begin

    tg:=i;

    i:=j;

    j:=tg;

    end; {buộc i<=j}

    K:=trunc(ln(j-i+1)/ln(2));

    If H[R[i,k]]

    else LCA:=R[j-1 shl k+1,k];

    End;

    Sau khi khởi tạo mảng R, function LCA(i,j) sẽ trả về giá trị là LCA của 2 nút i,j.

    Vấn đề còn lại là chứng minh tính đúng đắn của thuật toán trên:

    Gọi T=LCA(U,V). Giả sử trong quá trình DFS, U được xét tới trước V. Dựa vào thuật toán DFS suy ra trong mảng B từ vị trí của U tới vị trí của V chắc chắn chứa T và T là đỉnh thấp nhất. Vì nếu có đỉnh thấp hơn T thì quá trình DFS đã đi ra ngoài cây gốc T nên chắc chắn đã xét qua V. Như vậy, thuật toán trên là thuật toán đúng đắn.

    Độ phức tạp thuật toán là O(N) khởi tạo B + O(2Nlog(2*N)) khởi tạo RMQ và O(1) cho mỗi yêu cầu tìm LCA(u,v).

    Ngoài ra, RMQ còn ứng dụng trong tìm LCP – longest common prefix của 2 suffix khi sử dụng Suffix Array xin đề cập tới trong 1 tài liệu khác nói về suffix array.

    Bài tập:

    1. Cài đặt hoàn chỉnh 2 bài toán trên.

    2. Bài QTREE2 (SPOJ).

    Cho trước 1 cây với các cạnh vô hướng gồm N (N<= 10000) đỉnh, các cạnh được đánh số từ 1 tới N-1. Mỗi cạnh có 1 độ dài cạnh cho trước. Viết chương trình thực hiện 1 nhóm yêu cầu thuộc 1 trong 2 kiểu sau:

    DIST a b : hỏi khoảng cách giữa 2 nút a và b - tức là độ dài đường đi từ a tới b.

    KTH a b k: hỏi đỉnh thứ k trên đường đi từ a tới b.

    Input: Dòng đầu tiên ghi số N. Trong 1 số dòng tiếp theo mỗi dòng ghi 1 yêu cầu thuộc 1 trong 2 dạng yêu cầu trên. Input được kết thúc bởi 1 dòng ghi “DONE”.

    Output: Với mỗi yêu cầu ghi ra kết quả trên 1 dòng của file output.

    VD:

    Input

    6

    1 2 1

    2 4 1

    2 5 2

    1 3 1

    3 6 2

    DIST 4 6

    KTH 4 6 4

    DONE

    Output

    5

    3

    Đoàn Mạnh Hùng
    Manhhung741@yahoo.com

    School@net (Theo THNT)



     Bản để in  Lưu dạng file  Gửi tin qua email


    Những bài viết khác:



    Lên đầu trang

     
    CÔNG TY CÔNG NGHỆ TIN HỌC NHÀ TRƯỜNG
     
    Phòng 804 - Nhà 17T1 - Khu Trung Hoà Nhân Chính - Quận Cầu Giấy - Hà Nội
    Phone: 024.62511017 - 024.62511081
    Email: kinhdoanh@schoolnet.vn


    Bản quyền thông tin trên trang điện tử này thuộc về công ty School@net
    Ghi rõ nguồn www.vnschool.net khi bạn phát hành lại thông tin từ website này
    Site xây dựng trên cơ sở hệ thống NukeViet - phát triển từ PHP-Nuke, lưu hành theo giấy phép của GNU/GPL.