Category: Thuật toán

  • Sử dụng Python giải bài tập tổ hợp xác suất

    Sử dụng Python giải bài tập tổ hợp xác suất

    Sau khi đã giải được 20 Bài tập Python cơ bản có lời giải, mời bạn tiếp tục thử sức các bài tập Python chỉ sử dụng vòng lặp và các kiểu dữ liệu cơ bản như kiểu danh sách list, kiểu xâu str.

    Bài 1. [Đại học Thái Nguyên 2000] Từ các chữ số 1; 2; 3 có thể lập được bao nhiêu số tự nhiên gồm 5 chữ số có mặt đủ 3 chữ số nói trên?

    Đáp số: 150 số.

    Hướng dẫn. Đầu tiên sử dụng 5 vòng lặp để tạo một danh sách tất cả các số tự nhiên gồm 5 chữ số được tạo thành từ các chữ số 1, 2, 3. Sau đó duyệt qua tất cả các phần tử của danh sách này và dùng hàm membership in để kiểm tra xem phần tử đó có mặt cả ba chữ số 1, 2, 3 hay không. Nếu có thì tăng biến đếm count, và in phần tử đó ra nếu muốn.

    numbers = ['1', '2', '3']
    results = []
    
    for a in numbers:
      for b in numbers:
        for c in numbers:
          for d in numbers:
            for e in numbers:
              # results.append([a,b,c,d,e])
              results.append(a+b+c+d+e)
    
    count = 1
    
    for temp in results:
      # print(temp)
      if ('1' in temp) and ('2' in temp) and ('3' in temp):
        print(str(count) +': '+temp)
        count +=1

    Bài 2. Có bao nhiêu số tự nhiên gồm 5 chữ số và chia hết cho 7.

    Đáp số: 12857 số.

    Hướng dẫn. Sử dụng một biến đếm count. Duyệt tất cả các số tự nhiên có 5 chữ số (từ 10000 đến 99999) và kiểm tra xem số đó có chia hết cho 7 hay không. Nếu có thì tăng biến đếm. Có thể in ra số đó nếu muốn.

    count = 0
    for i in range(10000, 99999 + 1):	
      if (i % 7 == 0):
        count += 1
        print(str(count) + ': ' + str(i))

    Bài 3. Một em bé có thể mang họ cha là Nguyễn, hoặc họ mẹ là Lê; tên đệm có thể là Văn, Hữu hoặc Đình; tên có thể là Nhân, Nghĩa, Trí hoặc Dũng. Hỏi có bao nhiêu cách đặt tên cho bé?

    Đáp số. Có 24 cách đặt tên.

    bien_dem = 1
    ho = ['Nguyễn', 'Lê']
    dem = ['Văn', 'Hữu', 'Đình']
    ten = ['Nhân', 'Nghĩa', 'Trí', 'Dũng']
    for h in ho:
      for d in dem:
        for t in ten:
          print(str(bien_dem) + ': ' + h + ' ' + d + ' ' + t)
          bien_dem += 1

    Bài 4. [Đại học An Ninh 1997] Từ các chữ số từ 0 đến 6 có thể lập được bao nhiêu số tự nhiên chẵn gồm 3 chữ số khác nhau?

    Nếu sử dụng kiểu dữ liệu tập hợp set, chúng ta có thể in trực tiếp ra các số thỏa mãn yêu cầu:

    numbers_even = {'0', '2', '4', '6'}
    numbers_odd = {'1', '3', '5'}
    numbers = numbers_even | numbers_odd
    
    results = []
    count = 0
    
    for c in numbers_even:
      for a in (numbers - {'0'}):
        if (a != c):
          for b in numbers:
            if ( b!=a and b!= c):
              count += 1
              print(str(count) + ': ' +a+b+c)
    

    Cách khác, chúng ta không sử dụng kiểu dữ liệu tập hợp thì sẽ in ra rất cả các số tự nhiên chẵn sau đó loại đi các số mà có chữ số giống nhau:

    count = 0
    results =[]
    
    for a in range(1,7):
      for b in range(0,7):
        for c in {0,2,4,6}:
          results.append(str(a)+str(b)+str(c))
    
    temp = []
    for x in results:
      if not((x[0] == x[1]) or (x[0]==x[2]) or (x[1]==x[2])):
        temp.append(x)
    print(len(temp))
    print(temp)

    Bài 5. Từ các chữ số 0,1,2,3,4,5,6 có thể lập được bao nhiêu số tự nhiên gồm 3 chữ số khác nhau và phải có mặt chữ số 5?

    Đáp số: 80 số.

    count = 0
    results =[]
    
    for a in range(1,7):
      for b in range(0,7):
        for c in range(0,7):
          results.append(str(a)+str(b)+str(c))
    
    temp = []
    for x in results:
      if not((x[0] == x[1]) or (x[0]==x[2]) or (x[1]==x[2])) and ('5' in x):
        temp.append(x)
    print(len(temp))
    print(temp)

     

  • 150 bài Toán Tin

    150 bài Toán Tin

    150 bài Toán Tin

    Chúng tôi xin giới thiệu 150 bài Toán Tin của thầy Lê Minh Hoàng (ĐHSP Hà Nội) để bạn đọc tham khảo.

    01. TÍNH TOÁN SONG SONG

    Biểu thức đủ là một dãy ký tự gồm các biến ký hiệu bằng chữ cái thường tiếng Anh: a..z, các phép toán cộng ký hiệu +, nhân ký hiệu * và các dấu ngoặc (,). Được định nghĩa như sau:

    1. Mỗi biến a,b,…,z là một biểu thức đủ
    2. Nếu X và Y là biểu thức đủ thì (X+Y) và (X*Y) cũng là biểu thức đủ.
    3. Những biểu thức nào không xây dựng được theo 2 nguyên tắc trên không là biểu thức đủ.

    VD: Theo cách định nghĩa trên thì (a+(b+(c+d))) hoặc ((a+b)+(c*d)) là các biểu thức đủ.

    Cho biết thời gian tính phép + là P, thời gian tính phép * là Q, người ta định nghĩa thời gian tính toán một biểu thức đủ như sau:

    • Nếu biểu thức đủ chỉ gồm 1 biến (a..z) thì thời gian tính toán là 0
    • Nếu X và Y là 2 biểu thức đủ; thời gian tính X là TX thời gian tính Y là TY thì thời gian tính

    (X+Y) là max(TX,TY)+P thời gian tính (X*Y) là max(TX,TY)+Q

    Từ 1 biểu thức đủ người ta có thể biến đổi về một biểu thức tương đương bằng các luật:

    • Giao hoán: (X+Y) (Y+X); (X*Y) ⇔ (Y*X)
    • Kết hợp: (X+(Y+Z)) ((X+Y)+Z); (X*(Y*Z)) ⇔ ((X*Y)*Z)

    Yêu cầu: Cho trước một biểu thức đủ E dưới dạng xâu ký tự hãy viết chương trình:

    1. Tìm thời gian tính toán biểu thức E
    2. Hãy biến đổi biểu thức E thành biểu thức E’ tương đương với nó sao cho thời gian tính E’ là ít nhất có thể.

    Dữ liệu vào được đặt trong file văn bản PO.INP như sau:

    • Dòng thứ nhất ghi 2 số P, Q cách nhau 1 dấu cách (P,Q≤100)
    • Tiếp theo là một số dòng, mỗi dòng ghi 1 biểu thức đủ. Kết quả ra đặt trong file văn bản PO.OUT như sau:

    Với mỗi biểu thức E trong file PO.INP ghi ra file PO.OUT 3 dòng

    • Dòng thứ nhất: Ghi thời gian tính toán E
    • Dòng thứ hai: Ghi biểu thức E’
    • Dòng thứ ba: Ghi thời gian tính toán E’

    Chú ý: Để cho gọn, mỗi biểu thức đủ trong input/output file có thể viết mà không cần đến cặp dấu ngoặc ngoài cùng, dữ liệu vào được coi là đúng đắn và không cần kiểm tra.

    Ví dụ:

    150 bài Toán Tin 1

    02. BẢNG SỐ

    Cho một bảng hình chữ nhật kích thước M x N với M, N nguyên dương. M, N ≤ 50. Hình chữ nhật này được chia thành M x N ô vuông bằng nhau với kích thước đơn vị bởi các đường song song với các cạnh, trên ô vuông [i, j] ghi số nguyên A[i, j] (2 ≤ A[i, j] ≤ 50).

    Từ mảng A ta lập mảng B mà B[i, j] được xây dựng như sau:

    Biểu diễn số A[i, j] thành tổng các số nguyên tố với ràng buộc: trong biểu diễn đó có nhiều nhất chỉ một số nguyên tố xuất hiện hai lần. Trong các cách biểu diễn, chọn ra biểu diễn nhiều hạng tử nhất thì B[i, j] bằng số số hạng của biểu diễn này kể cả bội (nếu có).

    Ví dụ:

    Nếu A[i, j] = 10 = 2 + 3 + 5 thì B[i, j] = 3;

    Nếu A[i, j] = 12 = 2 + 2 + 3 + 5 thì B[i, j] = 4;

    Chú ý: Không được biểu diễn A[i, j] = 10 = 2 + 2 + 2 + 2 + 2 để có B[i, j] = 5 vì như vậy không thoả mãn ràng buộc

    1. Dữ liệu vào được cho bởi Text file INP trong đó:
      • Dòng đầu ghi hai số M, N
      • M dòng sau, dòng thứ i ghi N phần tử trên dòng i của bảng A: A[i, 1], A[i, 2], …, A[i, N] hai phần tử liên tiếp cách nhau ít nhất một dấu trống.
    2. Kết quả ghi ra Text file OUT.
      Giá trị bảng B, mỗi dòng của bảng ghi trên một dòng của file, hai phần tử liên tiếp cách nhau ít nhất một dấu trống.
    3. Hãy tìm hình chữ nhật lớn nhất được tạo bởi các ô mang giá trị bằng nhau của bảng B. Ghi tiếp ra file OUT.B1 một dòng gồm 5 số là: diện tích lớn nhất tìm được, toạ độ trên trái và dưới phải của hình chữ nhật có diện tích lớn nhất đó.

    03.   CARGO

    Bản đồ một kho hàng hình chữ nhật kích thước mxn được chia thành các ô vuông đơn vị (m hàng, n cột: các hàng đánh số từ trên xuống dưới, các cột đánh số từ trái qua phải). Trên các ô của bản đồ có một số ký hiệu:

    • Các ký hiệu # đánh dấu các ô đã có một kiện hàng xếp sẵn,
    • Một ký hiệu *: Đánh dấu ô đang có một xe đẩy
    • Một ký hiệu $: Đánh dấu ô chứa kiện hàng cần xếp
    • Một ký hiệu @: Đánh dấu vị trí ô mà cần phải xếp kiện hàng B vào ô đó
    • Các ký hiệu dấu chấm “.”: Cho biết ô đó trống

    Cần phải dùng xe đẩy ở * để đẩy kiện hàng ở $ đến vị trí @ sao cho trong quá trình di chuyển cũng như đay hàng, không chạm vào những kiện hàng đã được xếp sẵn. (Xe đay có thể di chuyển sang một trong 4 ô chung cạnh với ô đang đứng). Nếu có nhiều phương án thì chỉ ra một phương án sao cho xe đay phải di chuyển qua ít bước nhất.

    Các hướng di chuyển được chỉ ra trong hình dưới đây

    150 bài toán tin lê minh hoàng

    Dữ liệu: Vào từ file văn bản CARGO.INP

    • Dòng 1: Ghi hai số nguyên dương m, n cách nhau một dấu cách (m, n ≤ 80)
    • m dòng tiếp theo, dòng thứ i ghi đủ n ký hiệu trên hàng thứ i của bản đồ theo đúng thứ tự từ trái qua phải. Các ký hiệu được ghi liền nhau

    Kết quả: Ghi ra file văn bản CARGO.OUT

    • Dòng 1: Ghi số bước di chuyển xe đNy để thực hiện mục đích yêu cầu, nếu không có phương án khả thi thì dòng này ghi số -1
    • Dòng 2: Nếu có phương án khả thi thì dòng này ghi các ký tự liền nhau thể hiện hướng di chuyển của xe đNy R (East, West, South, North). Các chữ cái thường (e,w,s,n) thể hiện bước di chuyển không đNy hàng, các chữ cái in hoa (E,W,S,N) thể hiện bước di chuyển có đNy hàng.

    Ví dụ:

    150 bài Toán Tin 2

    04.   DÃY CON

    Cho một dãy gồm n ( n ≤ 1000) số nguyên dương A1, A2, …, An và số nguyên dương k (k ≤ 50). Hãy tìm dãy con gồm nhiều phần tử nhất của dãy đã cho sao cho tổng các phần tử của dãy con này chia hết cho k.

    Dữ liệu vào: file văn bản DAY.INP

    • Dòng đầu tiên chứa hai số n, k ghi cách nhau bởi ít nhất 1 dấu trống.
    • Các dòng tiếp theo chứa các số A1, A2, …, An được ghi theo đúng thứ tự cách nhau ít nhất một dấu trống hoặc xuống dòng (CR-LF).

    Kết quả: ghi ra file văn bản DAY.OUT

    • Dòng đầu tiên ghi m là số phần tử của dãy con tìm được.
    • Các dòng tiếp theo ghi dãy m chỉ số các phần tử của dãy đã cho có mặt trong dãy con tìm được. Các chỉ số ghi cách nhau ít nhất một dấu trắng hoặc một dấu xuống dòng.

    Ví dụ: 

    DAY.INP DAY.OUT
    10 3 9
    2 3 5 7 1 3 2 4 5
    9 6 12 7 6 7 10 8
    11 15

    05. XÂU FIBINACCI

    Xét dãy các xâu F1, F2, F3, …, FN, … trong đó:

    F1 = ‘A’

    F2 = ‘B’

    FK+1 = FK + FK-1 (K ³ 2).

    Ví dụ:

    F1 = ‘A’

    F2 = ‘B’ F3 = ‘BA’ F4 = ‘BAB’

    F5 = ‘BABBA’

    F6 = ‘BABBABAB’

    F7 = ‘BABBABABBABBA’

    F8 = ‘BABBABABBABBABABBABAB’

    F9 = ‘BABBABABBABBABABBABABBABBABABBABBA’

    Cho xâu S độ dài không quá 25, chỉ bao gồm các ký tự ‘A’ và ‘B’. Hãy xác định số lần xuất hiện xâu S trong xâu FN, N ≤ 35. Chú ý: hai lần xuất hiện của S trong FN không nhất thiết phải là các xâu rời nhau hoàn toàn.

    Dữ liệu: vào từ file văn bản FIBISTR.INP, bao gồm nhiều dòng, mỗi dòng có dạng N S. Giữa N và S có đúng 1 dấu cách. Dữ liệu vào là chuNn, không cần kiểm tra.

    Kết quả: Đưa ra file văn bản FIBISTR.OUT, mỗi dòng dữ liệu ứng với một dòng kết quả ra.

    06.   VÒNG SỐ NGUYÊN TỐ

    Một vòng tròn chứa 2n vòng tròn nhỏ (Xem hình vẽ). Các vòng tròn nhỏ được đánh số từ 1 đến n theo chiều kim đồng hồ. Cần điền các số tự nhiên từ 1 đến 2n mỗi số vào một vòng tròn nhỏ sao cho tổng của hai số trên hai vòng tròn nhỏ liên tiếp là số nguyên tố. Số điền ở vòng tròn nhỏ 1 luôn là số 1.

    vong so nguyen to

    Dữ liệu: Vào từ file văn bản CIRCLE.INP chứa số nguyên dương n (1 < n < 10)

    Kết quả: Ghi ra file văn bản CIRCLE.OUT:

    • Dòng đầu tiên ghi số lượng các cách điền số tìm được (k).
    • Dòng thứ i trong số k dòng tiếp theo ghi các số trong các vòng tròn nhỏ bắt đầu từ vòng tròn nhỏ 1 đọc theo thứ tự của các vòng tròn nhỏ.

    07.   ĐÔI BẠN

    Trước kia Tuấn và Mai là hai bạn cùng lớp còn bây giờ hai bạn học khác trường nhau. Cứ mỗi sáng, đúng 6 giờ cả hai đều đi từ nhà tới trường của mình theo con đường mất ít thời gian nhất (có thể có nhiều con đường đi mất thời gian bằng nhau và đều ít nhất). Nhưng hôm nay, hai bạn muốn gặp nhau để bàn việc họp lớp cũ nhân ngày 20-11.

    Cho biết sơ đồ giao thông của thành phố gồm N nút giao thông được đánh số từ 1 đến N và M tuyến đường phố (mỗi đường phố nối 2 nút giao thông). Vị trí nhà của Mai và Tuấn cũng như trường của hai bạn đều nằm ở các nút giao thông. Cần xác định xem Mai và Tuấn có cách nào đi thoả mãn yêu cầu nêu ở trên, đồng thời họ lại có thể gặp nhau ở nút giao thông nào đó trên con đường tới trường hay không ? (Ta nói Tuấn và Mai có thể gặp nhau tại một nút giao thông nào đó nếu họ đến nút giao thông này tại cùng một thời điểm). Nếu có nhiều phương án thì hãy chỉ ra phương án để Mai và Tuấn gặp nhau sớm nhất.

    Dữ liệu vào được đặt trong tệp FRIEND.INP:

    • Dòng đầu tiên chứa 2 số nguyên dương N, M (1 ≤ N ≤ 100);
    • Dòng tiếp theo chứa 4 số nguyên dương Ha, Sa, Hb, Sb lần lượt là số hiệu các nút giao thông tương ứng với: Nhà Tuấn, trường của Tuấn, nhà Mai, trường của
    • Dòng thứ i trong số M dòng tiếp theo chứa 3 số nguyên dương A, B, T. Trong đó A & B là hai đầu của tuyến đường phố i. Còn T là thời gian (tính bằng giây ≤ 1000) cần thiết để Tuấn (hoặc Mai) đi từ A đến B cũng như từ B đến A.

    Giả thiết là sơ đồ giao thông trong thành phố đảm bảo để có thể đi từ một nút giao thông bất kỳ đến tất cả các nút còn lại.

    Kết quả : Ghi ra tệp văn bản FRIEND.OUT

    • Dòng 1: Ghi từ YES hay NO tuỳ theo có phương án giúp cho hai bạn gặp nhau hay không. Trong trường hợp có phương án:
    • Dòng 2: Ghi thời gian ít nhất để Tuấn tới trường
    • Dòng 3: Ghi các nút giao thông theo thứ tự Tuấn đi qua
    • Dòng 4: Ghi thời gian ít nhất để Mai tới trường
    • Dòng 5: Ghi các nút giao thông theo thứ tự Mai đi qua
    • Dòng 6: Ghi số hiệu nút giao thông mà hai bạn gặp nhau
    • Dòng 7: Thời gian sớm nhất tính bằng giây kể từ 6 giờ sáng mà hai bạn có thể gặp nhau.

    Các số trên một dòng của Input/Output file ghi cách nhau ít nhất một dấu cách.

    Ví dụ : Với sơ đồ giao thông sau: (N=6,M=7, Ha=1, Sa=6, Hb=2, Sb=5)

    150 bài Toán Tin 3

    08.   CỬA SỔ VĂN BẢN

    Xét văn bản T gồm N ký tự (N ≤ 1000000, N không cho trước) và văn bản P gồm M ký tự (0 < M ≤ 100). Cửa sổ độ dài W là một đoạn văn bản gồm W ký tự liên tiếp của T (M < W ≤ 1000). Nói cửa sổ W chứa mẫu P nếu tồn tại một cách xoá một số ký tự liên tiếp của W để nhận được P.

    Hai cửa sổ của T gọi là khác nhau nếu chúng bắt đầu từ những vị trí khác nhau trong T. Hãy xác định số cửa sổ khác nhau trong văn bản T chứa P.

    Dữ liệu:

    • File văn bản INP
    • Dòng đầu chứa hai số nguyên W, M
    • Dòng thứ hai chứa M ký tự của văn bản P;
    • File TXT chứa văn bản T

    Kết quả:

    Đưa ra file WINDOW.OUT một số nguyên xác định số cửa sổ tìm được theo yêu cầu.

    Lưu ý: Đa số trường hợp, file WINDOWT.TXT không phải là Text file, có nghĩa là nó chứa các ký tự trong khoảng  #0..#255 (file of Char). Như vậy tính cả CR(#13) và LF(#10)

    Ví dụ:
    WINDOWP.INP WINDOWT.TXT WINDOW.OUT
    4 2

    is

    This is a sample text for the

    first task on the contest

    8

    09. VÒNG TRÒN CON

    Cho hai dãy số nguyên a1, a2, …, am và b1, b2, …, bn (2 ≤ m, n ≤ 100)

    Các số này được xếp quanh hai vòng tròn A và B: các số ai quanh vòng tròn A và các số bj quanh vòng tròn B. Vòng tròn C được gọi với các số quanh nó c1, c2, …, cp được gọi là vòng tròn con của A (hoặc của B) nếu tồn tại một cách xoá bớt các số của A (hoặc của B) để được vòng tròn C. Hãy tìm vòng tròn C là vòng tròn con của cả A và B với số phần tử (p) lớn nhất có thể.

    Chú ý: Các số trên 3 vòng tròn A, B, C được xếp theo đúng thứ tự trong dãy theo cùng một chiều kim đồng hồ.

    Dữ liệu: Vào từ file văn bản CIRCLE.INP

    • Dòng đầu chứa hai số nguyên m, n cách nhau ít nhất một dấu cách.
    • m dòng tiếp theo, dòng thứ i ghi số ai
    • n dòng tiếp theo, dòng thứ j ghi số bj

    Kết quả: Đưa ra file văn bản CIRCLE.OUT

    • Dòng đầu ghi số nguyên p
    • p dòng sau, dòng thứ k ghi số ck.

    10.   BỐ TRÍ PHÒNG HỌP

    Có n cuộc họp đánh số từ 1 đến n đăng ký làm việc tại một phòng hội thảo. Cuộc họp i cần được bắt đầu ngay sau thời điểm si và kết thúc tại thời điểm fi. Hỏi có thể bố trí phòng hội thảo phục vụ được nhiều nhất bao nhiêu cuộc họp, sao cho khoảng thời gian làm việc của hai cuộc họp bất kỳ là không giao nhau.

    Dữ liệu vào từ file văn bản ACTIVITY.INP

    • Dòng đầu tiên chứa số nguyên dương n ( n ≤ 10000)
    • Dòng thứ i trong số n dòng tiếp theo chứa hai số nguyên dương si, fi (si < fi ≤ 32000) (i: 1 ≤ i ≤n).

    Kết quả: Ghi ra file ACTIVITY.OUT

    • Dòng đầu tiên ghi số K là số các cuộc họp được chấp nhận phục vụ
    • K dòng tiếp theo liệt kê số hiệu các cuộc họp được chấp nhận theo thứ tự từ cuộc họp đầu tiên tới cuộc họp cuối cùng , mỗi dòng ghi số hiệu một cuộc họp.

    11.   MUA VÉ TÀU HOẢ

    Tuyến đường sắt từ thành phố A đến thành phố B đi qua một số nhà ga. Tuyến đường có thể biểu diễn bởi một đoạn thẳng, các nhà ga là các điểm trên đó. Tuyến đường bắt đầu từ A và kết thúc ở B, vì thế các nhà ga sẽ được đánh số bắt đầu từ A (có số hiệu là 1) và B là nhà ga cuối cùng.

    Giá vé đi lại giữa hai nhà ga chỉ phụ thuộc vào khoảng cách giữa chúng. Cách tính giá vé được cho trong bảng sau đây:

    Khoảng cách giữa hai nhà ga (X) Giá vé
    0 < X ≤ L1 C1
    L1 < X ≤ L2 C2
    L2 < X ≤ L3 C3

    Vé để đi thẳng từ nhà ga này đến nhà ga khác chỉ có thể đặt mua nếu khoảng cách giữa chúng không vượt quá L3. Vì thế nhiều khi để đi từ nhà ga này đến nhà ga khác ta phải đặt mua một số vé. Hơn thế nữa, nhân viên đường sắt yêu cầu hành khách chỉ được giữ đúng một vé khi đi trên tàu và vé đó sẽ bị huỷ khi hành khách xuống tàu.

    Ví dụ, trên tuyến đường sắt cho như sau:

    bai toan tin mua ve tau hoa

    Để đi từ ga 2 đến ga 6 không thể mua vé đi thẳng. Có nhiều cách mua vé để đi từ ga 2 đến ga 6: Chẳng hạn đặt mua vé từ ga 2 đến ga 3 mất chi phí C2 sau đó mua vé từ ga 3 đến ga 6 mất chi phí C3, và chi phí tổng cộng khi đi theo cách này là C2 + C3. Hoặc mua vé từ ga 2 đến ga 4 mất chi phí C2, sau đó mua vé từ ga 4 đến ga 5 mất chi phí C2 và mua vé từ ga 5 đến ga 6 mất chi phí C1, như vậy chi phí tổng cộng là 2C2 + C1. Lưu ý rằng mặc dù khoảng cách giữa ga 2 và ga 6 bằng 12 = 2 L2 nhưng không được phép mua 2 vé với giá C2 để đi thẳng từ ga 2 đến ga 6.

    Yêu cầu: Tìm cách đặt mua vé để đi lại giữa hai nhà ga cho trước với chi phí mua vé là nhỏ nhất.

    Dữ liệu vào từ file văn bản RTICKET.INP

    • Dòng đầu tiên ghi các số nguyên L1, L2, L3, C1, C2, C3 (1 ≤ L1 < L2 < L3 ≤ 109; 1 ≤ C1 < C2 < C3≤ 109) theo đúng thứ tự liệt kê ở trên.
    • Dòng thứ hai chứa số lượng nhà ga N ( 2 ≤ N ≤ 10000).
    • Dòng thứ ba ghi hai số nguyên s, f là các chỉ số của hai nhà ga cần tìm cách đặt mua vé với chi phí nhỏ nhất để đi lại giữa chúng.
    • Dòng thứ i trong số N – 1 dòng tiếp theo ghi số nguyên là khoảng cách từ nhà ga A (ga 1) đến nhà ga thứ i + 1. Chi phí ít nhất từ nhà ga đầu tiên A đến nhà ga cuối cùng B không vượt quá 109.

    Kết quả ghi ra file văn bản RTICKET.OUT chi phí nhỏ nhất tìm được.

    12.   XIN CHỮ KÝ

    Giám đốc một công ty trách nhiệm hữu hạn muốn xin chữ ký của ông Kiến trúc sư trưởng thành phố phê duyệt dự án xây dựng trụ sở làm việc của công ty. Ông kiến trúc sư trưởng chỉ ký vào giấy phép khi bà thư ký của ông ta đã ký duyệt vào giấy phép. Bà thư ký làm việc tại tầng thứ M của toà nhà trụ sở làm việc gồm M tầng của Văn phòng Kiến trúc sư trưởng thành phố. Các tầng của toà nhà được đánh số từ 1 đến M, từ thấp đến cao. Mỗi tầng của toà nhà có N phòng được đánh số từ 1 đến N từ trái qua phải. Trong mỗi phòng chỉ có một nhân viên làm việc. Giấy phép chỉ được bà thư ký ký duyệt khi đã có ít nhất một nhân viên ở tầng M đã ký xác nhận. Ngoài bà thư ký, một nhân viên bất kỳ chỉ ký xác nhận vào giấy phép khi có ít nhất một trong các điều kiện sau được thoả mãn:

    1. Nhân viên đó làm việc ở tầng 1
    2. Giấy phép đã được ký xác nhận bởi nhân viên làm việc ở cùng số phòng trong tầng sát dưới
    3. Giấy phép đã được ký xác nhận bởi nhân viên làm việc ở cùng số phòng trong tầng sát trên
    4. Giấy phép đã được ký xác nhận bởi nhân viên làm việc ở phòng bên cạnh

    Mỗi một nhân viên (kể cả bà thư ký) khi ký xác nhận đều đòi một khoản lệ phí. Hãy chỉ ra cách xin được chữ ký của Kiến trúc sư trưởng đòi hỏi tổng lệ phí phải trả là nhỏ nhất (giả thiết rằng riêng chữ ký của Kiến trúc sư trưởng không mất lệ phí).

    Dữ liệu vào từ file văn bản SIGN.INP

    • Dòng đầu tiên chứa ba số M, N, P (1 ≤ M ≤ 50; 1 ≤ N ≤ 100; 1 ≤ P ≤ N) ở đây P là số phòng bà thư ký.
    • Dòng thứ i trong số M dòng tiếp theo chứa N số nguyên dương theo thứ tự là lệ phí phải trả cho các nhân viên ở các phòng 1, 2, …, N trên tầng Các số này không vượt quá 109 và giả thiết rằng tổng chi phí cần trả cũng không vượt quá 109.

    Kết quả: Ghi ra file văn bản SIGN.OUT 

    • Dòng đầu tiên ghi 2 số F, K theo thứ tự là chi phí cần trả và số lượng phòng cần đi qua.
    • K dòng tiếp theo, mỗi dòng ghi số tầng và số phòng của một phòng theo thứ tự cần đi qua. (Các số trên 1 dòng của input/output file cách nhau ít nhất 1 dấu trống)

    13.   LẮC NẠM KIM CƯƠNG

    Lắc là một đồ trang sức rất được các cô gái ưa chuộng. Chính vì vậy mà chúng phải được chế tạo thật đẹp và đa dạng. Xét việc chế tạo lắc có m mắt xích, mỗi mắt được nạp một viên kim cương. Có n loại viên kim cương khác nhau, n ≤ 7; 2  ≤  m  ≤  27-n + 19.

    Hai lắc được gọi là khác nhau nếu ta không thể tìm cách đặt sao cho các mắt tương ứng có kim cương cùng loại. Lưu ý rằng lắc có hình vòng.

    Với m và n cho trước, hãy xác định xem có thể tồn tại bao nhiêu loại lắc khác nhau.

    Các loại kim cương được ký hiệu là A, B, C, … Một cấu hình lắc được xác định bởi một xâu m ký tự A, B, C, … và bắt đầu bằng ký tự nhỏ nhất.

    Cho số thứ tự l, hãy xác định cấu hình tương ứng (Các cấu hình được sắp xếp theo thứ tự từ điển).

    Dữ liệu: Vào từ file BRASLET.INP có dạng

    m n l1

    l2

    Kết quả: Đưa ra file BRASLET.OUT

    K – Số lượng lắc khác nhau s1

    s2

    … (si xác định cấu hình lắc tương ứng với li)

    14.   RẢI SỎI

    Xét trò chơi rải sỏi với một người chơi như sau: Cho cây T và một đống sỏi gồm K viên ở mỗi bước người ta lấy 1 viên sỏi từ đống sỏi và đặt vào một nút lá tuỳ chọn.

    Nếu nút p có r nút lá và tất cả và tất cả các nút lá đều có sỏi thì người ta gom tất cả các viên sỏi ở lá lại, đặt 1 viên ở nút p, xoá các nút lá của nó và hoàn trả r – 1 viên sỏi còn lại vào đống sỏi.

    Trò chơi kết thúc khi đã đặt được 1 viên sỏi vào nút gốc.

    Nhiệm vụ đặt ra là theo cấu trúc của cây T, xác định số viên sỏi tối thiểu ban đầu để trò chơi có thể kết thúc bình thường. Cây có n nút ( N ≤ 400), nút gốc được đánh số là 1.

    Dữ liệu: vào từ file văn bản STONE.INP

    • Dòng đầu: số n
    • Dòng thứ i trong số n dòng tiếp theo có dạng: i m i1 i2 … im. Trong đó m là số nút con của nút i; i1, i2, …, im: Các nút con của nút i.

    Kết quả: đưa ra file STONE.OUT số lượng viên sỏi tối thiểu cần thiết

    15.   ĐIỆP VIÊN

    Địa bàn hoạt động của một điệp viên là một khu phố mà ở đó chỉ có các đường phố ngang, dọc tạo thành một lưới ô vuông. Với mục đích bảo mật, thay vì tên đường phố, điệp viên đánh số các phố ngang từ 0 đến m và các phố dọc từ 0 đến n. ở một số ngã ba hoặc ngã tư có các trạm kiểm soát. Anh ta đang đứng ở nút giao của hai đường (i1, j1) (j1 – đường ngang; i1 – đường dọc) và cần tới điểm hẹn ở giao của hai đường (i2, j2). Để tránh bị theo dõi, đường đi phải không qua các trạm kiểm soát và cứ tới chỗ rẽ thì nhất thiết phải đổi hướng đi, thậm chí có thể sang đường và đi ngược trở lại. Việc đổi hướng chỉ được thực hiện ở ngã ba hoặc ngã tư. Hãy xác định đường đi ngắn nhất tới điểm hẹn hoặc cho biết không có đường đi đáp ứng được yêu cầu đã nêu.

    Dữ liệu: vào từ file SPY.INP

    Dòng đầu: m n i1 j1 i2 j2 ( 0 ≤ m, n ≤ 100)

    Các dòng sau: mỗi dòng 2 số i, j (toạ độ trạm kiểm soát).

    Kết quả: đưa ra file SPY.OUT

    Dòng đầu: độ dài đường đi ngắn nhất hoặc thông báo NO nếu không có đường đi.

    Các dòng sau: mỗi dòng 2 số i, j chỉ nút tiếp theo cần tới theo đường đi tìm được, bắt đầu là i1 j1 và kết thúc là i2 j2.

    16.   KHOẢNG CÁCH GIỮA HAI XÂU

    Cho hai xâu ký tự S1 và S2, mỗi xâu có độ dài không quá 100 ký tự. Cho phép thực hiện các phép biến đổi sau đây đối với xâu ký tự:

    1. Thay thế một ký tự nào đó bởi ký tự khác
    2. Đổi chỗ hai ký tự liền nhau
    3. Chèn một ký tự vào sau vị trí nào đó
    4. Xoá bớt 1 ký tự

    Ta gọi khoảng cách giữa hai xâu S1 và S2 là số ít nhất các phép biến đổi nêu trên cần áp dụng đối với xâu S1 để biến nó thành xâu S2.

    Yêu cầu: Tính khoảng cách giữa 2 xâu S1, S2 cho trước và chỉ ra thứ tự các phép biến đổi.

     Ví dụ: Giả sử S1 = ‘Barney’; S2 = ‘brawny’. Khoảng cách giữa 2 xâu là 4. Dãy các phép biến đổi cần thực hiện là:

    1. Thay ký tự 1 của S1 (B) bởi b
    2. Đổi chỗ ký tự thứ 2 (a) và thứ 3 (r) của S1.
    3. Chèn ký tự w vào S1 sau ký tự thứ
    4. Xoá ký tự thứ 5 của S1.

    Dãy các phép biến đổi có thể mô tả như sau:

    ‘Barney’ ® ‘barney’ ® ‘braney’ ® ‘brawney’ ® ‘brawny’

    Dữ liệu: vào từ file văn bản STREDIT.INP có cấu trúc như sau:

    • Dòng đầu tiên chứa xâu S1
    • Dòng thứ hai chứa xâu S2

    Kết quả: Ghi ra file văn bản STREDIT.OUT

    • Dòng đầu tiên ghi số lượng các phép biến đổi cần sử dụng K
    • Mỗi dòng i trong số K dòng tiếp theo mô tả phép biến đổi được sử dụng ở lần thứ i gồm các tham số sau: các tham số ghi trên 1 dòng ghi cách nhau 1 dấu cách.
      • 1, P, C (nếu là phép thay ký tự tại vị trí P bằng ký tự C)
      • 2, I, I + 1 (nếu là phép đổi chỗ 2 ký tự thứ I và thứ I + 1)
      • 3, P, C (nếu là phép chèn ký tự C vào sau vị trí P)
      • 4, P (nếu là phép xoá ký tự thứ P)

    17.   XẾP LẠI BẢNG SỐ

    Cho một bảng ô vuông gồm m hàng và n cột. Các ô được đánh chỉ số theo (hàng, cột) từ (0, 0) đến (m – 1, n – 1). Trên m x n ô người ta viết các số tự nhiên từ 0 đến m x n – 1 theo một thứ tự tuỳ ý. Cho phép đổi chỗ hai số đặt trong hai ô ở thế mã giao chân. Cần tìm cách đổi chỗ các số sao cho thu được bảng có tính chất: Số ở ô (i, j) là n x i + j.

    Dữ liệu vào từ file văn bản BOARD.INP: các số ghi trên 1 dòng cách nhau ít nhất 1 dấu trống.

    • Dòng đầu ghi 2 số m, n (5 ≤ m, n ≤ 80)
    • m dòng tiếp theo, dòng thứ i ghi n số tự nhiên theo đúng thứ tự các số ghi trên hàng i của bảng.

    Kết quả đưa ra file BOARD.OUT

    • Dòng thứ i chứa 4 số X1, Y1, X2, Y2 cho biết tại bước thứ i cần đổi chỗ 2 số tại hai ô (X1, Y1) và (X2, Y2)

    18.   THĂM KHU TRIỂN LÃM

    Một khu triển lãm nghệ thuật có mxn phòng được bố trí trong một hình chữ nhật kích thước mxn (2≤m,n≤ 20). Mỗi phòng biểu diễn bởi một ô và đều có cửa thông với các phòng chung cạnh với nó. Với mỗi một phòng, ta đánh chỉ số theo toạ độ (x, y) của ô (1 ≤hàng x≤m; 1≤cột y≤n) và gán cho nó một chữ cái in hoa (‘A’..’Z’) thể hiện loại nghệ thuật trưng bày tại phòng đó. Có thể vào khu triển lãm ở các phòng có toạ độ (x bất kỳ, y = 1) và có thể đi ra ở các phòng có toạ độ (x bất kỳ, y = n)

    150 bài Toán Tin 4
    Ví dụ với m=10 và n=11

    Một vị thủ tướng đi thăm triển lãm có sở thích đặc biệt với một loại nghệ thuật. Yêu cầu của ông ta “rất đơn giản” là không nhất thiết phải đi thăm tất cả các phòng chứa loại nghệ thuật mà ông ta thích nhưng không được đi qua các phòng chứa loại nghệ thuật khác.

    Ví dụ: Để đi thăm loại nghệ thuật B, Thủ tướng có thể đi:

    (1,1), (1,2), (1,3), (1,4), (1,5), (1,6), (2,6), (3,6), (4,6), (4,7), (4,8), (4,9), (4,10), (5,10), (6,10),(6,11).

    Nhưng không phải luôn tồn tại đường đi như vậy, ví dụ : nếu Thủ tướng muốn đi thăm loại nghệ thuật A thì không thể tìm được một đường đi (Bởi cột 6 của bảng không có một chữ A nào).

    Để có đường đi của vị thủ tướng đi thăm loại nghệ thuật A thì những người quản lý triển lãm phải tìm cách đổi loại nghệ thuật tại hai phòng nào đó. Trong ví dụ này thì để có đường đi chúng ta có thể đổi loại nghệ thuật B ở phòng (5,6) cho loại nghệ thuật A ở phòng (3,1) hoặc phòng (3,7), (3,8),

    Trong những cách đổi đó, người ta thường quan tâm đến việc phải đổi sao cho tổng số phòng phải đổi là ít nhất có thể được. Trong những cách đổi với số cặp phòng phải đổi ít nhất hãy chỉ ra cách đổi mà con đường thủ tướng phải đi là ngắn nhất có thể được. Có thể có nhiều nghiệm thì chỉ cần chỉ ra một nghiệm.

    Dữ liệu vào từ file văn bản TL.INP bao gồm:

    • Dòng đầu tiên ghi số m, n
    • Dòng thứ hai ghi một chữ cái in hoa thể hiện loại nghệ thuật thủ tướng muốn thăm.
    • m dòng tiếp theo, dòng thứ i là một xâu ký tự độ dài n biểu diễn các loại nghệ thuật trong các phòng trên hàng i theo đúng thứ tự từ cột 1 đến cột n.

    Kết quả cho ra file văn bản TL.OUT bao gồm:

    • Dòng đầu tiên là số cặp phòng cần đổi (p).
    • p dòng tiếp theo mỗi dòng gồm 4 số a, b, c, d có nghĩa là ta cần đổi loại nghệ thuật tại phòng (a,b) cho phòng (c,d).
    • Dòng tiếp theo ghi số phòng trên con đường đi ngắn nhất tìm được (q).
    • q dòng tiếp theo, mỗi dòng ghi toạ độ x,y thể hiện cho con đường ngắn nhất đó theo đúng thứ tự phòng đi qua.
    • Nếu không tồn tại phương án đổi phòng để có đường đi thì ghi vào file OUT một dòng:

    NO SOLUTION

    Ví dụ: Với khu triển lãm như trên:

    TL.INP TL.OUT
    10 11 0
    B 16
    BBBBBBFFFFF 1 1
    AAAAABDCCFF 1 2
    AFFFABAACFC 1 3
    BFEFABBBBBD 1 4
    FFDEABAAABA 1 5
    EEDEEEEEABB 1 6
    DDDEEEEEAAB 2 6
    DCCFFFCCABA 3 6
    DCCFFFCCAAA 4 6
    CCCCCCCCCCC 4 7
    4 8
    4 9
    4 10
    5 10
    6 10
    6 11

      

    TL.INP TL.OUT
    10 11 1
    A 5 6 3 1
    BBBBBBFFFFF 18
    AAAAABDCCFF 2 1
    AFFFABAACFC 2 2
    BFEFABBBBBD 2 3
    FFDEABAAABA 2 4
    EEDEEEEEABB 2 5
    DDDEEEEEAAB 3 5
    DCCFFFCCABA 4 5
    DCCFFFCCAAA 5 5
    CCCCCCCCCCC 5 6
    5 7
    5 8
    5 9
    6 9
    7 9
    8 9
    9 9
    9 10
    9 11

    19.   DÒ MÌN

    Cho một bãi mìn kích thước mxn ô vuông, trên một ô có thể có chứa một quả mìn hoặc không, để biểu diễn bản đồ mìn đó, người ta có hai cách:

    • Cách 1: dùng bản đồ đánh dấu: sử dụng một lưới ô vuông kích thước mxn, trên đó tại ô (i, j) ghi số 1 nếu ô đó có mìn, ghi số 0 nếu ô đó không có mìn
    • Cách 2: dùng bản đồ mật độ: sử dụng một lưới ô vuông kích thước mxn, trên đó tại ô (i, j) ghi một số trong khoảng từ 0 đến 8 cho biết tổng số mìn trong các ô lân cận với ô (i, j) (ô lân cận với ô (i, j) là ô có chung với ô (i, j) ít nhất 1 đỉnh).

    Giả thiết rằng hai bản đồ được ghi chính xác theo tình trạng mìn trên hiện trường.

    Ví dụ: Bản đồ đánh dấu và bản đồ mật độ tương ứng: (m = n = 10)

    150 bài Toán Tin 5

    Về nguyên tắc, lúc cài bãi mìn phải vẽ cả bản đồ đánh dấu và bản đồ mật độ, tuy nhiên sau một thời gian dài, khi người ta muốn gỡ mìn ra khỏi bãi thì vấn đề hết sức khó khăn bởi bản đồ đánh dấu đã bị thất lạc !!. Công việc của các lập trình viên là: Từ bản đồ mật độ, hãy tái tạo lại bản đồ đánh dấu của bãi mìn.

     Dữ liệu: Vào từ file văn bản MINE.INP, các số trên 1 dòng cách nhau ít nhất 1 dấu cách

    • Dòng 1: Ghi 2 số nguyên dương m, n (2 ≤ m, n ≤ 80)
    • m dòng tiếp theo, dòng thứ i ghi n số trên hàng i của bản đồ mật độ theo đúng thứ tự từ trái qua phải.

    Kết quả: Ghi ra file văn bản MINE.OUT, các số trên 1 dòng ghi cách nhau ít nhất 1 dấu cách

    • Dòng 1: Ghi tổng số lượng mìn trong bãi
    • m dòng tiếp theo, dòng thứ i ghi n số trên hàng i của bản đồ đánh dấu theo đúng thứ tự từ trái qua phải.

    Các bài tiếp theo, mời bạn đọc tải tại đây 150 BAI TOAN TIN – LE MINH HOANG

  • Bài tập HSG Tin học THPT

    Bài tập HSG Tin học THPT

    Chúng tôi xin giới thiệu 16 Bài tập HSG Tin học THPT gồm các bài tập: Điệp viên, Trư bát giới, Bàn cờ 4 * 4, Đội cờ, Hệ thống xe buýt, Bố trí phòng họp, Phân phối kênh, Trò chơi với ô chữ, Công việc, Mã hoá Burrows wheeler, Mặt phẳng, Truyền tin ngắn nhất, Robot quét vôi, Vườn Táo, Dãy lồi.

    Quý thầy cô và các em học sinh có thể tham khảo thêm Giải thuật Đệ quy là gì?

    1. Bài tập HSG Tin học THPT: Điệp viên

    Một điệp viên trưởng phụ trách một nước nọ trước khi về nước muốn gặp nhân viên của mình để nghe báo cáo. Hai người đang ở hai thành phố khác nhau vì vậy họ phải di chuyển để gặp nhau. Quy tắc di chuyển như sau:

    • Họ di chuyển vào ban ngày và nghỉ tại một thành phố vào buổi tối.
    • Trong ngày, họ chỉ có thể di chuyển từ một thành phố tới thành phố bên cạnh (có đường đi trực tiếp và các đường đi này là 1 chiều).
    • Để bảo đảm an toàn, các điệp viên luôn luôn di chuyển (không dừng tại một thành phố quá một đêm).
    • Hai người có thể gặp nhau nếu họ ở cùng1 thành phố vào buổi tối.

    Yêu cầu: Lập chương trình kiểm tra xem hai người có gặp nhau không.

    Dữ liệu: agent.inp

    • Dòng đầu ghi 2 số: n là số thành phố, m là số các đường đi trực tiếp giữa các thành phố (n <=50, m<=100).
    • Dòng tiếp theo là 2 số p, q là vị trí hiện thời của hai điệp viên.
    • M dòng tiếp theo mỗi dòng chứa 2 số ai, aj là số hiêu các thành phố và từ ai có đường đi trực tiếp (một chiều) đến aj.

    Kết quả: agent.out

    • Nếu 2 người không gặp nhau in ra từ “No”
    • Nếu 2 người gặp nhau in ra t là số ngày ngắn nhất mà hai người có thể gặp nhau.

    Ví dụ:

    Agent.in1 Agent.ou1 Agent.in2 Agent.ou2 Agent.in3 Agent.ou3 Agent.in4 Agent.ou4
    6 7

    1 5

    1 2

    4 5

    2 3

    3 4

    4 1

    5 4

    5 6

    3 3 3

    1 3

    1 2

    2 3

    3 1

    No 8 9

    1 8

    1 2

    2 3

    3 4

    4 1

    1 5

    5 6

    6 7

    7 8

    8 1

    5 8 9

    2 8

    1 2

    2 3

    3 4

    4 1

    1 5

    5 6

    6 7

    7 8

    8 1

    11

    Hướng dẫn: Sử dụng thuật toán: Loang theo lớp

    Bài toán này là một điển hình cho thuật toán “loang theo lớp”. Ta loang theo chiều rộng đường đi của 2 điệp viên theo trình tự: loang đường đi của người thứ nhất tại thời điểm i một lần rồi loang đường đi của người thứ hai tại thời điểm đó một lần. Lặp lại việc loang  đó cho đến khi không thể loang được tiếp hoặc kiểm tra thấy 2 người gặp nhau (tức cả 2 bên loang cùng đến được một địa điểm) hoặc kiểm tra thấy một đỉnh nào đó lặp lại quá nhiều một số lần cho phép (tức người đó rơi vào một chu trình mà không thể gặp được người kia) hay nếu queue vơi giới hạn cao cũng không thể chứa được nữa.

    Giả mã

    While Not Stop Do
       Begin
       Loangr1(đau1, cuoi1, Stop1);
       Loangr2(đau2,cuoi2, Stop2);
       If  kiemtra (dau1, cuoi1, dau2, cuoi2) then begin found := true; break end;
       Stop := Stop 1 or Stop2;
    End;

    Trong chương trình con Loangr1(dau1, cuoi1, Stop1) đó biến stop1 trả giá trị true nếu chưa vượt quá giới hạn queue1solanlaplai[i] < Ghanchophep (co the là 10000 – tuy theo ban thich đo chinh xac nao).

    Hàm Loangr2(đau2,cuoi2, Stop2) cũng tương tự.

    Hàm Kiemtra (dau1, cuoi1, dau2, cuoi2) tra gia tri true nếu với các đỉnh được đi đến (vừa kết nạp vào queue1 và queue 2) trong lần loangr1 (co cuoi1 – dau1 đỉnh) và trong lần loangr2 (có cuoi2 – dau2 đỉnh) có một đỉnh chung.

    2. Bài tập HSG Tin học THPT: Trư bát giới

    Trên đường đi thỉnh kinh, một lần Bát Giới được Tôn Ngộ Không giao cho nhiệm vụ đi hầu Tam Tạng. Tam Tạng đi với tốc độ không đổi và đường đi của ông là đường gấp khúc (có thể tự cắt) gồm n điểm gãy. Mỗi điểm gãy được cho bởi cặp số nguyên (xi, yi) là toạ độ trên mặt phẳng xoy. Theo hầu Tam Tạng, Bát Giới đi chơi theo con đường riêng của mình nhưng luôn gặp Tam Tạng tại n điểm gãy nói trên. Hai người bắt đầu xuất phát từ điểm (x1, y1) và kết thúc chuyến đi đồng thời tại điểm (xn, yn) để chờ Tôn Ngộ Không và Sa Tăng. Bát Giới có thể đi với tốc độ không vượt quá hai lần tốc độ của Tam Tạng. Khi Tam Tạng đi theo đường thẳng từ điểm gãy này đến điểm gãy kế tiếp, Bát Giới có thể chạy đến các điểm hấp dẫn được cho bởi m cặp số nguyên (x’i, y’i). Tuy nhiên, sau khi tách rời Sư phụ tại điểm (xi, yi) Bát Giới chỉ có thể thăm không quá một điểm hấp dẫn ông để rồi gặp lại Sư phụ tại điểm (xi+1, yi+1).

    Yêu cầu:

    Tìm đường đi của Bát Giới thoả mãn các điều kiện nêu trên và sao cho số điểm hấp dẫn của Bát Giới thăm được là nhiều nhất.

    Dữ liệu: Bg.inp.

    • Dòng đầu tiên chứa hai số nguyên dương n và m (2n100, 0m100)
    • Dòng thứ hai chứa n cặp số nguyên: x1, y1, …, xn, yn.
    • Dòng thứ ba chứa m cặp số nguyên: x’1, y’1, …, x’m, y’m.

    Các điểm trong file dữ liệu là khác nhau từng đôi một và toạ độ của chúng là các số nguyên có trị tuyệt đối không vượt quá 1000. Các số ghi cách nhau bởi dấu cách.

    Kết quả: Bg.out.

    • Dòng đầu tiên ghi số nguyên dương k là số điểm gãy trên đường đi của Bát Giới.
    • Dòng thứ hai ghi cặp toạ độ u1, v1, …, uk, vk biểu diễn đường đi của Bát Giới. Các toạ độ ghi cách nhau bởi dấu cách..

    Ví dụ:

    Bg.INP Bg.OUT
    4 5

    1 4 5 7 5 2 -2 4

    -4 -2 3 9 1 2 -1 3 8 -3

    6

    1 4 3 9 5 7 5 2 1 2 -2 4

    Hướng dẫn:

    Dùng cặp ghép

    • Xây dựng tập X: tập các gồm n – 1 phần tử. Với các phần tử đó là các cạnh trên đường đi của Bát Giới.
    • Xây dựng tập Y: tập gồm m phần tử. Các phần tử là các điểm hấp dẫn.
    • Xây dựng ma trận quan hệ giữa X và Y. Nếu ở phần tử i (i của tập X – tức là các cạnh trên đường đi của Tam Tạng), Bát Giới có thể đi đến điểm hấp dẫn j (j thuộc Y) thì a[i,j] = true và ngược lại. Tức là a[i,j] = true ó kc(xi, yi, x’j, y’j) + kc(xi+1, yi+1, x’j, y’j) 2kc(xi, yi, xi+1, yi+1).
    • Dùng thuật toán cặp ghép tối đa để giải.

    3. Bài tập HSG Tin học THPT: Bàn cờ 4 * 4

    Một bàn cờ có dạng bảng vuông kích thước 4 * 4, trên đó có một số quân cờ. Một quân cờ chỉ có thể di chuyển sang 1 ô kề cạnh còn trống, mỗi di chuyển như vậy được gọi là 1 bước di chuyển. Cho hai trạng thái của bàn cờ, hãy chỉ ra một dãy các bước di chuyển để đưa bảng từ trạng thái xuất phát đến trạng thái đích với số phép di chuyển là ít nhất. Mỗi trạng thái được mô tả là một ma trận 4 * 4 trong đó số ô ở hàng I, cột j là 1 nếu tại vị trí (i,j) tương ứng có quân cờ đang đứng hoặc bằng 0 nếu không có.

    Dữ liệu: chess.inp

    • Gồm 2 * 4 dòng thể hiện ma trận mô tả trạng thái xuất phát và trạng thái đích. 4 dòng đầu tiên thể hiện ma trận xuất phát, 4 dòng tiếp theo là ma trận đích.
    • Input luôn đảm bảo là có nghiệm.

    Kết quả: chess.out

    • Dòng đầu tiên ghi k là số ít nhất các phép biến đổi tìm được.
    • K dòng tiếp, mỗi dòng mô tả 1 phép biến đổi, theo đúng trình tự biến đổi, gồm 4 số nguyên dương u, v, x, y thể hiện di chuyển quân cờ ở vị trí (u, v) sang vị trí (x, y).

    Ví dụ:

    Chess.inp Chess.out
    1111

    1111

    0000

    0000

    0000

    0000

    1111

    1111

    16

    2 1 3 1

    1 1 2 1

    2 2 3 2

    1 2 2 2

    2 3 3 3

    1 3 2 3

    2 4 3 4

    1 4 2 4

    3 1 4 1

    2 1 3 1

    3 2 4 2

    2 2 3 2

    3 3 4 3

    2 3 3 3

    3 4 4 4

    2 4 3 4

    4. Bài tập HSG Tin học THPT: Đội cờ             

    Có hai đội cờ vua A và B thi đấu với nhau. Mỗi đội cử ra n kì thủ, mỗi kì thủ của đội B chỉ đấu một trận và đấu với 1 kì thủ của đội A và ngược lại. Vậy có tất cả n trận đấu. Đội nào thắng được 2 điểm, hoà được 1 điểm và thua không được điểm nào.

    Cho đội B được quyền chọn cặp thi đấu.

    Yêu cầu: lập trình để đội B chọn được các cặp thi đấu sao cho tổng số điểm của đội B là cao nhất. Cho biết trình độ của kì thủ thứ i của hai đội A và B là ai và bi (I = 1, 2, …, n) và giả sử trong thi đấu, hai kì thủ có trình độ bằng nhau sẽ hoà và cầu thủ nào có trình độ cao hơn sẽ thắng.

    Dữ liệu: Doico.inp

    • Dòng đầu ghi số nguyên dương n (1n10000).
    • Trên dòng thứ I trong số n dòng tiếp theo ghi hai số nguyên dương ai, bi (1ai, bi1000), cách nhau một khoảng trắng.

    Kết quả: Doico.out

    • Dòng đầu là số nguyên t là tổng số điểm cao nhất mà đội B có thể đạt được.
    • Trên dòng thứ hai là n số nguyên dương xi, trong đó xi là số thứ tự của kì thủ đội B phải đấu với kì thủ thứ i của đội A để tổng số điểm đội B đạt được là lớn nhất.

    Ví dụ:

    Doico.inp Doico.out
    4

    7 8

    5 6

    4 3

    9 4

    5

    1 2 4 3

    Hướng dẫn thuật giải:

    • Sắp xếp hai mảng A, B theo thứ tự không giảm, nhớ lưu vị trí cũ của A, B vào hai mảng chỉ số.
    • Ta thực hiện phương pháp tối ưu từng bước, cụ thể:
    • Ở chương trình này cần chú ý khi sắp xếp 2 dãy A, B thì vị trí các kì thủ đã đổi, do đó mảng x là mảng ứng với vị trí mới của mảng A và B ta cần đổi về vị trí cũ.

    5. Bài tập HSG Tin học THPT: Hệ thống xe buýt.

    Một hệ thống các xe buýt có nhiệm vụ chuyên chở hành khách đi lại giữa một số ga sao cho đảm bảo tính liên thông hai chiều giữa các ga này. Hệ thống bao gồm một số tuyến đường, mỗi tuyến đường gồm một số ga khác nhau theo thứ tự mà xe buýt đi qua. Xe buýt thuộc tuyến đường nào chỉ chạy trên tuyến đường đó, lần lượt qua các ga thuộc tuyến cho đến hết, sau đó lại quay đầu chạy theo hướng ngược lại. Có thể có một số ga chung cho một số tuyến đường. Một hành khách muốn đi từ ga đầu đến ga cuối, có thể đi trên một tuyến hoặc phải chuyển tuyến một số lần ở những nơi có ga chung. Bài toán đặt ra là, cần tìm một hành trình cho phép đi từ ga đầu đến ga cuối sao cho số lần phải chuyển tuyến là ít nhất. Nếu tồn tại nhiều phương án như vậy, hãy tìm phương án đi qua ít ga nhất.

    Dữ liệu: busway.inp

    • Dòng đầu là số tuyến đường.
    • Các dòng tiếp mỗi dòng mô tả một tuyến đường, gồm một chuỗi các kí tự viết liền nhau, mỗi kí tự mô tả một tên ga theo đúng thứ tự các ga tren tuyến (chú ý các ga trên cùng một tuyến là khác nhau, nhưng các ga trên các tuyến khác nhau có thể trùng nhau, tên ga có thể là một kí tự bất kì hiển thị được trong bảng mã ACSII)
    • Dòng tiếp theo là số hành trình cần tìm.
    • Các dòng tiếp theo, mỗi dòng mô tả một hành trình cần tìm, gồm cặp kí tự viết liền nhau, xác định các tên ga đầu và ga cuối.

    Giả thiết các dữ liệu là hợp lệ, không cần kiểm tra. Giới hạn kích thước 100 cho số các tuyên đường và 50 cho số các ga trên cùng một tuyến đường.

    Kết quả: busway.out

    • Mỗi hành trình được viết trên một dòng, gồm các kí tự biểu diễn tên ga viết theo thứ tự đi được. Các tên ga này được viết thành từng nhóm theo tuyến đường: nếu thuộc cùng một tuyến thì viết liền nhau, nếu sang tuyến khác thì viết cách nhau một dấu cách (space), tên ga chung được viết lặp lại.

    Ví dụ

    Busway.inp Busway.out
    3

    ABC

    DBE

    GAEH

    2

    HC

    GB

    HEA ABC

    GA AB

    Hướng dẫn:

    • Xây dựng đồ thị đường đi giữa các ga là ma trận hai chiều (lưu vào mảng trọng số a). Coi mỗi kí tự là một đỉnh của đồ thị (dùng hàm ord(kítự) lấy giá trị là số). a[i,j] = 0 nếu các kí tự “chr(i)”, “ chr(j)” (cũng là các ga) không thuộc cùng một tuyến đường nào cả. a[i,j] > 0 và là giá trị nhỏ nhất của đoạn đường đi giữa hai ga (chr(i), chr(j)).
    • Dùng thuật toán Dijstra để tìm đường đi ngắn nhất từ ga đầu tới ga cuối. Trong thuật toán ta có hai ưu tiên sau:
      • Số ga giữa đường đi là ít nhất (ưu tiên cao nhất).
      • Tổng đường đi giữa các ga là nhỏ nhất.
    • Với ưu tiên thứ nhất ta có thể coi đồ thị vừa lập là một đồ thị mới: đồ thị quan hệ: a[i,j] = 0 tức không có đường đi từ i tới j và a[i,j] > 0 tức có đường đi giữa i và j. Với ưu tiên thứ nhất ta coi a[i,j] > 0 thì a[i,j] = 1 trong đồ thị mới lập.
    • Khi ưu tiên thứ nhất được thoả mãn ta xét đến ưu tiên thứ hai, khi đó coi như thuật toán Dijstra dùng cho đồ thị cũ đã lập lúc đầu – đồ thị trọng số.

    6. Bài tập HSG Tin học THPT: Bố trí phòng họp.

    Có n cuộc họp được đánh số từ 1 đến n đăng kí làm việc tại một phòng hội thảo. Cuộc họp i cần bắt đầu vào thời điểm ai và kết thúc vào thời điểm bi (i = 1..n). Hai cuộc họp có thể nhận phục vụ nếu các khoảng thời gian làm việc tương ứng chỉ có thể giao nhau tại đầu mút hoặc tách rời nhau.

    Yêu cầu: Hãy tìm một lịch cho phòng hội thảo để có thể phục vụ nhiều cuộc họp nhất.

    Dữ liệu:  Activity.inp.

    • Dòng đầu tiên là giá trị n (n <= 1000000).
    • Dòng thứ i trong n dòng tiếp theo ghi 2 số ai và bi cách nhau ít nhất một dấu cách. (ai, bi <=32000 và là các số nguyên dương).

    Kết quả: Activity.out.

    • Dòng đầu tiên ghi số k là số cuộc họp tối đa có thể bố trí.
    • Dòng tiếp theo ghi số hiệu của cuộc họp được phục vụ theo trình tự lịch bố trí.

    Ví dụ:

    Activity.inp Activity.out
    5

    1 3

    2 4

    1 6

    3 5

    7 9

    3

    1 4 5

    Hướng dẫn:

    Do n lớn nên ta cần lưu dữ liệu theo mảng thời gian.

    Khai báo:        tr: array [1..32000] of integer;

    Dùng mảng trước đánh dấu thời gian cuối của cuộc họp. Tức là nếu tr[c]  <> 0 thì tồn tại cuộc họp có thời điểm kết thúc là c và tr[c] mang ý nghĩa là thời điểm ban đầu của cuộc họp. Đọc dữ liệu và đánh dấu mảng tr sao cho tr[c] gần c nhất có thể.

    Với cuộc họp có thời điểm kết thúc c mà ta chọn, ta cần lưu chỉ số của cuộc họp đó.

    Khai báo:        Cs: array [1..32000] of longint; {vì n lớn}.

    Do mảng này không thể khai báo được -> lưu chỉ số theo 2 giá trị: n div 32, n mod 32 -> thay mảng cs bằng hai mảng sau:

    Khai báo:        Trx, try: array [1..32000] off integer

    Ý nghĩa  :        trx[c] = I div 32; try[c] := I mod 32.

    Mảng try có thể khai báo bằng kiểu byte. Hai mảng này dùng mảng động.

    Xử lí: Gọi max là thời gian kết thúc lớn nhất trong các cuộc họp. Duyệt từ 1 đến max, nếu có cuộc họp i nào có tr[i] >= cuối thì kết nạp vào mảng lưu. Với cuoi là giá trị thời gian kết thúc của cuộc họp được chọn trước đó (đầu tiên cuối = 0).

    7. Bài tập HSG Tin học THPT: Phân phối kênh

    Công ty dịch vụ mạng máy tính cần phân phối kênh hoạt động phục vụ n yêu cầu của khách hàng (n <= 5000) đánh số thứ tự từ 1 tới n. Với mỗi khách hàng thứ i ta biết khoảng thời gian yêu cầu sử dụng kênh là (si, ti), i =1, 2, …, n (khách hàng sẽ sử dụng kênh từ thời điểm si tới thời điểm ti). Thời gian chuyển giao kênh từ khách hàng này tới khách hàng khác là không đáng kể. Như vậy, nếu hai khách hàng nào đó được bố trí làm việc trên cùng một kênh thì các khoảng thời gian sử dụng của họ chỉ có thể có nhiều nhất là một điểm chung.

    Yêu cầu: hãy tìm cách phân phối sử dụng ít kênh nhất.

    Dữ liệu: Chanel.inp

    • Dòng đầu tiên ghi số n.
    • Dòng thứ i trong số n dòng tiếp theo mỗi dòng ghi 2 số nguyên dương si, ti (i =1, 2, …, n).

    Kết quả: Chanel.out

    • Dòng đầu tiên ghi số lượng kênh cần sử dụng p.
    • Mỗi dòng thứ i trong số p dòng tiếp theo chứa các chỉ số của mỗi khách hàng sử dụng kênh thứ i, i = 1, 2, …, p.

    Ví dụ:

    Chanel.inp Chanel.out
    7

    0 3

    3 5

    6 8

    0 7

    7 8

    0 2

    2 6

    3

    4 5

    1 2 3

    6 7

    Hướng dẫn.

    Ở bài này ta cần xác định các khách hàng với khoảng thời gian (si, ti) đó vào các tập sao cho các khoảng thời gian trong mỗi tập chỉ có thể có duy nhất là một điểm chung và số tập là ít nhất có thể được. Ta sắp xếp lại các khoảng thời gian đó theo thứ tự tăng dần của si, nếu si, sj bằng nhau thì sắp xếp theo thứ tự tăng dần của ti, tj … Khi đó ta duyệt các khách hàng theo thứ tự từ 1 tới n, với mỗi khách hàng thì ta duyệt các tập đã xây dựng được, nếu có thể kết nạp khách hàng này vào tập hợp nào thì ta kết nạp vào (và có thể thấy đó là cách kết nạp tối ưu do hiệu quả của sắp xếp), nếu không thì cho khách hàng này vào tập hợp mới. Ta thấy độ phức tạp của thuật toán chỉ cỡ .

    8. Bài tập HSG Tin học THPT: Trò chơi với ô chữ.

    Tiếp tục phát triển trò chơi với ô chữ, người ta đã đánh số cho các từ có độ dài từ 1 đến 26 theo quy tắc là ưu tiên độ dài từ, sau đó là theo vần ABC. Với:

    a                      1

    b                      2

    z                      26

    aa                    27

    snowfall          157.118.051.752

    Như vậy, mỗi một số ta có tương ứng là một từ gồm các chữ cái thường và ngược lại ứng với mỗi từ ta có một số tương ứng. Công việc đặt ra là: giả sử ta có một số hãy tìm từ tương ứng với nó, và cho một từ hãy cho biết từ đó ứng với số bao nhiêu.

    Dữ liệu: Game.inp.

    • Dòng đầu là một số nguyên.
    • Dòng thứ hai là một xâu kí tự (gồm các kí tự thường).

    Kết quả: Game.out.

    • Dòng thứ nhất là một từ tương ứng với số trong file input.
    • Dòng thứ hai là một số tương ứng với từ trong file input.

    Ví dụ:

    Game.inp Game.out
    157118051752

    snowfall

    snowfall

    157118051752

    9. Bài tập HSG Tin học THPT: Công việc

    Có n công viêc đánh số từ 1 đến n, n <= 10000. Mỗi việc làm đều phải làm liên tục trong một giờ mới xong. Việc u nếu làm không muộn hơn giờ thứ du sẽ thu được một giá trị nguyên dương gu; các giá trị du, gu nguyên dương và không lớn hơn 60000. Tại mỗi thời điểm không được làm hơn một việc và bắt đầu từ thời điểm 0, giờ thứ I xem như bắt đầu từ thời điểm I – 1.

    Yêu cầu: Hãy chọn một số việc làm sao cho tổng giá trị thu được là lớn nhất. Các số phát sinh trong phạm vi longint.

    Dữ liệu: Job.inp

    • Dòng thứ nhất ghi số n.
    • N dòng tiếp theo, dòng thứ u ghi hai số du, gu.

    Kết quả: Job.out

    • Dòng thứ nhất ghi tổng giá trị thu được.
    • Tiếp theo là các dòng, mỗi dòng ghi hai số x, y với ý nghĩa việc x làm trong giờ thứ y.

    Ví dụ:

    Job.inp Job.out
    6

    3 7

    3 20

    1 10

    1 15

    1 5

    3 3

    42

    3

    2 3

    4 1

    1 2

    10. Bài tập HSG Tin học THPT: Mã hoá Burrows wheeler.

    Burrows Wheeler đề xuất phương pháp mã hóa thông tin như sau: ví dụ cần mã hóa BANANA, các bước tiến hành là:

    • Bước 1: Từ cần mã hóa được dịch chuyển vòng tròn và tạo thành một ma trận l * l kí tự, trong đó l là độ dài của từ.
    • Bước 2: Sắp xếp lại các dòng của ma trận theo thứ tự từ điển.
    • Bước 3: trích xâu từ các kí tự cuối của cột, thông báo xâu này và cho biết từ gốc là thứ mấy trong ma trận nhận được ở bước 2. Ta có: (NNBAAA, 4).

    BANANA                               ABANAN

    ANANAB                               ANABAN

    NANABA                               ANANAB

    ANABAN                               BANANA

    NABANA                               NABANA

    ABANAN                               NANABA.

    Yêu cầu: cho kết quả mã hóa (kết quả bước 3). Hãy xác định từ ban đầu.

    Dữ liệu: mahoa.inp:

    • Bao gồm một hoặc nhiều nhóm 2 dòng , dòng đầu là xâu kí tự độ dài không quá 100, dòng sau là số nguyên dương cho biết vị trí từ gốc.

    Kết quả: mahoa.out:

    • Xuất ra các từ ban đầu, mỗi từ trên 1 dòng.

    Ví dụ:

    Mahoa.inp Mahoa.out
    NNBAAA

    4

    OMOEULCG

    1

    BANANA

    COGUMELO

    11. Bài tập HSG Tin học THPT: Mặt phẳng

    Trên mặt phẳng cho n hình chữ nhật có cạnh song song với trục toạ độ. Hãy đếm số miền mặt phẳng được tạo ra bởi các cạch của hình chữ nhật. Một miền mặt phẳng là một vùng liên tục khép kín giới hạn bởi các cạnh của hình chữ nhật và không chứa một miền mặt phẳng nào khác.

    Dữ liệu: Matphang.inp.

    Dòng đầu là số nguyên dương n (<30) là số hình chữ nhật.

    N dòng tiếp theo, mỗi dòng chứa 4 số nguyên dương lần lượt là toạ độ theo hai trục toạ độ của hai đỉnh đối của hình chữ nhật.

    Kết quả: Matphang.out.

    Số miền mặt phẳng tìm được.

    Ví dụ:

    Matphang.inp Matphang.out
    2

    10 10 30 30

    20 20 40 40

    3

     

    Matphang.inp Matphang.out
    2

    20 10 30 40

    10 20 40 30

    5

    12. Bài tập HSG Tin học THPT: Truyền tin ngắn nhất.

    Trong một mạng gồm n máy tính đánh số từ 1 đến n. Sơ đồ nối mạng được cho bởi hệ thống gồm m kênh nối trực tiếp giữa một số cặp máy trong mạng. Biết chi phí truyền cho 1 đơn vị thông tin theo mỗi kênh nối của mạng.

    Người ta cần chuyển 1 bức thông điệp từ máy s -> t. Để đảm bảo an ninh, người ta muốn chuyển bức thông điệp này theo 2 đường truyền tin khác nhau (tức là không có kênh nào của mạng được sử dụng trong cả 2 đường truyền tin). Chi phí của 1 đường truyền được hiểu là tổng chi phí trên các kênh của nó.

    Yêu cầu: giả sử bức thông điệp có độ dài một đơn vị thông tin, hãy tìm cách chuyển thông điệp từ s -> t sao cho tổng chi phí chuyển thông tin ( bằng tổng chi phí theo cả hai đường truyền tin) là nhỏ nhất.

    Dữ liệu: May.inp

    • Dòng đầu ghi n, m, s, t cách nhau bởi dấu cách (n<=100).
    • Mỗi dòng thứ i trong số m dòng tiếp theo ghi thông tin về kênh nối thứ i của mạng gồm 3 số di, ci, gi: di, ci là chỉ số 2 máy tương ứng và gi là chi phí để truyền theo kênh này (đường truyền là hai chiều).

    Kết quả: May.out

    • Dòng đầu ghi tổng chi phí.
    • Dòng thứ hai ghi đường truyền 1: s-> t.
    • Dòng thứ ba ghi đường truyền 2: s ->t.

    Ví dụ:

    May.inp May.out
    5 7 15

    1 2 3

    1 4 8

    2 3 5

    2 4 4

    3 5 5

    4 3 8

    4 5 3

    24

    1 2 3 5

    1 4 5

    13. Bài tập HSG Tin học THPT: Robot quét vôi

    Có 9 căn phòng (đánh số từ 1 đến 9) đã được quét vôi với mầu trắng, xanh hoặc vàng. Có 9 rôbôt (đánh số từ 1 đến 9) phụ trách việc quét vôi các phòng. Mỗi rôbôt chỉ quét vôi một số phòng nhất định. Việc quét vôi được thực hiện nhờ một chương trình cài sẵn theo qui tắc:

    • nếu phòng đang có mầu trắng thì quét mầu xanh,
    • nếu phòng đang có mầu xanh thì quét mầu vàng,
    • nếu phòng đang có mầu vàng thì quét mầu trắng.

    Cần phải gọi lần lượt một số các rôbôt ra quét vôi (mỗi lần một rôbôt, một rôbôt có thể gọi nhiều lần và có thể có rôbôt không được gọi. Rôbôt được gọi sẽ quét vôi tất cả các phòng mà nó phụ trách) để cuối cùng các phòng đều có mầu trắng. Hãy tìm một phương án như vậy sao cho lượng vôi phải quét là ít nhất. Giả thiết rằng luợng vôi cho mỗi lượt quét đối với các phòng là như nhau.

    Dữ liệu: đọc từ file văn bản ROBOT.INP gồm các dòng:

    • 9 dòng đầu, mỗi dòng mô tả danh sách các phòng được quét vôi bởi một rôbôt theo thứ tự từ rôbôt 1 đến rôbôt 9. Mỗi dòng như vậy gồm các số hiệu phòng viết sát nhau. Chẳng hạn dòng thứ 2 có nội dung:
      3578 mô tả rôbôt 2 phụ trách việc quét vôi các phòng 3, 5, 7, 8.
    • dòng cuối mô tả mầu vôi ban đầu của các phòng. Dòng gồm 9 ký tự viết sát nhau, ký tự thứ i biểu diễn mầu vôi của phòng i với quy ước: ký tự T chỉ mầu trắng, ký tự X chỉ mầu xanh, ký tự V chỉ mầu vàng.

    Kết quả: đưa ra file văn bản ROBOT.OUT gồm một dòng dưới dạng:

    • nếu không có phương án thì ghi một chữ số 0,
    • trái lại ghi dãy thứ tự các rôbôt được gọi (các số hiệu rôbôt viết sát nhau).

    Thí dụ: 

    ROBOT.INP   ROBOT.OUT
    159

    123

    357

    147

    5

    369

    456

    789

    258

    XVXVXVTXT

    2455688

    14. Bài tập HSG Tin học THPT

    Cho 2 xâu:

    X = x1x2..xM. (Với xi là các kí tự số từ ‘0’ đến ‘9’)

    Y = y1y2..yN.( Với yi là các kí tự số từ ‘0’ đến ‘9’)

    (M, N <= 250)

    Ta gọi: Z = z1z2..zk là xâu chung của 2 xâu X, Y nếu xâu Z nhận đ­ợc từ xâu X bằng cách xoá đi một số kí tự và cũng nhận được từ xâu Y bằng cách xoá đi một số kí tự.

    Yêu cầu: Tìm một xâu chung của 2 xâu X, Y sao cho xâu nhận được tạo thành một số lớn nhất có thể được.

    Dữ liệu vào file: String.inp

    Gồm 2 dòng, dòng 1 là xâu X, dòng 2 là xâu Y.

    Kết quả ra file: String.out

    Gồm 1 dòng duy nhất là số lớn nhất có thể nhận được.

    Ví dụ:

    String.inp String.out
    19012304 034012 34

    15. Bài tập HSG Tin học THPT: Vườn Táo

    Trong một mảnh vờn hình vuông cạnh 1000 m có trồng N cây táo . Vị trí mỗi cây táo đợc xác định bởi toạ độ (x,y) trong hệ toạ độ vuông góc với gốc toạ đọ là góc trái dới của vờn và các trục toạ độ song song với các cạnh vờn . Hãy tìm hình chữ nhật lớn nhất sao cho các cạnh song song với các cạnh của vờn , và trong nó không chứa cây táo nào ( mà chỉ có thể chứa trên biên ) .

    Dữ Liệu vào từ file     Tao.Inp

    • Dòng thứ nhất ghi N số từ 1 đến 600 .
    • Trong N dòng sau mỗi dòng ghi hai số nguyên dơng x,y ,0<x,y<1000 là toạ độ của các cây táo .

    Kết Quả ghi ra file   Tao.Out

    • Dòng thứ nhất ghi diện tích hình chữ nhật
    • Dòngthứ hai ghi số hai số là toạ độ của đỉnh trái dới
    • Dòng thứ ba ghi hai số là toạ độ của đỉnh trên phải của hình chữ nhật .

    Ví Dụ:

    TAO.INP

    7 280 100 200 600 400 200 135 800 800 400 600 800 900 210

    TAO.OUT

    360000 200 200 800 800

    Hướng dẫn.

    Ta thêm vào tập các cây những cây giả là hình chiếu của các cây thật trên bốn cạnh của khu vờn . Sắp xếp lại các cây theo thứ tự tăng dần của hoành độ . Thực chất ta đã chia chúng thành các hình nhỏ hơn . Sau đó tìm từng hình một thoả mãn điều kiện của hình chữ nhật ( không chứa táo , diện tích lớn nhất ) .

    16. Bài tập HSG Tin học THPT Dãy lồi

    Dãy giá trị nguyên A=(a1, a2, …, an) được gọi là dãy lồi nếu nó giảm dần từ a1 tới ai nào đó, rồi tăng dần tới an. Ví dụ: dãy 10 5 4 2 -1 4 6 8 12 là dãy lồi.

    Yêu cầu: lập trình nhập vào một dãy số nguyên, bằng cách xoá bớt một số phần tử của dãy và giữ nguyên trình tự các phần tử còn lại, ta nhận được dãy con lồi dài nhất.

    Dữ liệu: dayloi.inp.

    • Dòng đầu là số tự nhiên n (n<=5000).
    • Dòng tiếp theo là n số nguyên của dãy số(các số kiểu integer).

    Kết quả: dayloi.out.

    • Dòng đầu tiên ghi số phần tử lớn nhất của dãy con tìm được (ghi ra 0 nếu không tồn tại dãy lồi).
    • Dòng tiếp theo ghi các số thuộc dãy con (không thay đổi trật tự các phần tử trong dãy ban đầu).

    Ví dụ:

    Dayloi.inp Dayloi.out
    10

    1 2 3 4 2 5 1 2 3 4

    6

    4 2 1 2 3 4

  • 100 ĐỀ THI HỌC SINH GIỎI TIN HỌC – ĐỀ THI TIN HỌC TRẺ

    100 ĐỀ THI HỌC SINH GIỎI TIN HỌC – ĐỀ THI TIN HỌC TRẺ

    Bài 1: Viết chương trình nhập vào tọa độ tâm I(a;b) và bán kính r của một đường tròn (a, b, r là các số nguyên). Sau đó nhập vào một điểm A(x, y) bất kì và kiểm tra xem nó có thuộc đường tròn hay không?

    Bài 2: Viết chương trình tính tích xy (với x, y là hai số thực có độ lớn tùy ý).

    Bài 3: Tìm tất cả các chữ số có ba chữ số, sao cho tổng các lập phương của các chữ số thì bằng chính số đó.

    Bài 4: Nhập 3 loại tiền và số tiền cần đổi. Hãy tìm tất cả các tổ hợp có được của 3 loại tiền trên cho số tiền vừa nhập.

    Bài 5: Viết chương trình giải bài toán cổ sau:

    Trăm trâu trăm cỏ
    Trâu đứng ăn năm
    Trâu nằm ăn ba
    Trâu già ba con một bó.

    Hỏi có bao nhiêu con mỗi loại?

    Bài 6: Lập tam giác PASCAL, dùng chương trình con.

    Bài 7: Viết các chương trình con  tính diện tích tam giác, tròn, vuông, chữ nhật trong một chương trình. Sau  đó hỏi chọn  một trong các phương án  tính diện  tích bằng  cách chọn trong bảng chọn lệnh sau:

    1. Không làm gì hết và trở về màn hình soạn thảo.
    2. Tính diện tích hình vuông
    3. Tính diện tích hình tròn
    4. Tính diện tích tam giác
    5. Tính diện tích hình chữ nhật

    Bài 8: Viết chương trình nhập vào một dãy số nguyên   có n phần tử. In ra màn hình phần tử nhỏ nhất, phần tử lớn nhất và giá trị trung bình của danh sách ra màn hình.

    Bài 9: Viết chương trình nhập vào một dãy số nguyên  có n phần tử.

    1. Đưa những phần tử lẻ ra đầu danh sách, những phần tử chẵn về cuối danh sách và in kết quả ra màn hình.
    2. Sắp xếp các phần tử lẻ đầu danh sách theo thứ tứ tăng dần, sắp xếp các phần tử chẵn cuối danh sách theo thứ tự giảm dần. In danh sách ra màn hình.

    Bài 10: Viết chương trình nhập vào một chuỗi kí tự, sau đó nhập vào một kí tự bất kì và đếm số lần của nó trong chuỗi đã nhập.

    Bài 11: Viết chương trình nhập vào một chuỗi ký tự. Kiểm tra xem nó có đối xứng hay không (Ví dụ: Chuỗi đối xứng RADAR, MADAM).

    Bài 12: Viết chương trình nhập vào họ tên của một người. Sau đó in chuỗi họ tên ra màn hình với các ký tự đầu đổi thành chữ hoa, toàn bộ chuỗi họ và tên đổi thành chữ hoa.

    Bài 13: Viết chương trình nhập vào một dãy số nguyên  có n phần tử.

    1. Sắp xếp dãy theo thứ tự tăng dần và in kết quả ra màn hình.
    2. Nhập vào một số x bất kì, đếm số lần xuất hiện của nó trong dãy trên.
    3. In ra màn hình số phần tử nhỏ hơn hoặc bằng x.
    4. In ra màn hình số phần tử lớn hơn x.

    Bài 14: Sử dụng lệnh lặp để tính tổng của 11 số hạng đầu tiên

    S = 100 + 105 + 110  +...

    Bài 15:  Tìm số P, biết rằng

    P/4 = 1 - 1/3   + 1/5 - 1/7  +...

    Với độ chính xác: |1/2n-1| < 10^-5

    Bài 16: Cho một dãy số nguyên A(i) với i=1,...N. Viết chương trình:

    1. Tính và in ra trung bình cộng cuả các số dương trong dãy.
    2. Đếm xem có bao nhiêu số chia hết cho 3.
    3. In ra vị trí các số bằng 0 (nếu có) trong dãy đã cho.

    Bài 17:  Viết chương trình tìm các số có 3 chữ số mà tổng lập phương các chữ số của nó bằng chính nó (các số Amstrong).

    Bài 18:  Nhập một số thực x rồi tính

    S = 1 + x/1! + x^2/2! + x^3/3! +...+ x^n/n!

    với độ chính xác | x^n/n! | < 10^-5.

    Bài 19:  Dãy Fibonaxi được định nghĩa như sau:

    A1=A2=1, An=A(n-1) + A(n-2) với n>=2.

    Hãy:

    1. Nhập một số n và in ra n số Fibonaxi đầu tiên.
    2. Nhập một số n và in ra các số Fibonaxi nhỏ hơn hoặc bằng n.

    Bài 20:  Cho một dãy số. Viết chương trình:

    1. Gom tất cả các số chia hết cho 7 về đầu dãy và tất cả các số chia hết cho 5 vể cuối dãy.
    2. Sắp xếp phần số đã gom theo thứ tự tăng dần.

    Bài 21:   Cho một dãy số. Hãy viết chương trình Tìm phần tử nhỏ nhất và phần tử nhỏ thứ hai. Hãy cho biết vị trí đầu tiên của phần tử lớn nhất.

    Bài 22: Cho một dãy ký tự. Hãy viết chương trình tách dãy trên thành hai nửa, nửa đầu gồm các số, nửa sau là các chữ cái. Sắp xếp nửa đầu giảm dần, nửa sau tăng dần.

    Bài 23: Xét dãy các xâu F1, F2,... Fn trong đó:

    F1 = 'A'; F2 = 'B'; Fk+1 = Fk + F(k-1) với k=>2

    Ví dụ:

    F1 = 'A'
    F2 = 'B'
    F3 = 'BA'
    F4 = 'BAB'
    F5 = 'BABBA'
    F6 = 'BABBABAB'...

    Cho xâu S độ dài không quá 25, chỉ bao gồm các kí tự 'A''B'. Yêu cầu:

    1. Hãy xác định số lần xuất hiện xâu S trong xâu Fn, n<=35. Chú ý: Hai lần xuất hiện của S trong Fn không nhất thiết phải là các xâu rời nhau hoàn toàn.
    2. Dữ liệu vào: Đọc từ file văn bản FIBISTR.INP có cấu trúc như sau: Gồm nhiều dòng, mỗi dòng gồm nS. Giữa nS có đúng 1 dấu cách. Dữ liệu vào là chuẩn, không cần kiểm tra.
    3. Dữ liệu ra: Ghi ra file văn bản FIBISTR.OUT có cấu trúc như sau: Gồm nhiều dòng, mỗi dòng dữ liệu ứng với một dòng kết quả ra.

    Bài 24: SỐ PHẢN NGUYÊN TỐ. Một số tự nhiên n được gọi là số phản nguyên tố nếu nó có nhiều ước số nhất trong n số tự nhiên đầu tiên.

    Yêu cầu: Cho số K không vượt quá 10000. Ghi ra số phản nguyên tố lớn nhất nhỏ hơn hoặc bằng K.

    Dữ liệu vào: Đọc từ file văn bản OPNT.INP có cấu trúc như sau:

    • Dòng đầu tiên là số M (1<M<=100) là số lượng các số cần tìm số phản nguyên tố lớn nhất của nó.
    • M dòng tiếp theo là các số K1,K2,..KM

    Dữ liệu ra: Ghi ra file văn bản SOPNT.OUT có cấu trúc như sau:

    • Gồm M dòng.
    • Dòng thứ i (1<=i<=M) là số phản nguyên tố lớn nhất nhỏ hơn hoặc bằng Ki.

    Bài 25: Ngồi nhà quá rỗi, Sơn có ý tưởng dùng các que diêm tạo thành các số hập phân. Một cách đại diện cho 10 chữ số thập phân như sau:

    ĐỀ THI HỌC SINH GIỎI TIN HỌC - ĐỀ THI TIN HỌC TRẺ

    Cho N que diêm, Sơn có thể tạo ra một loạt các chữ số. Sơn kinh gạc phát hiện ra số nhỏ nhất và lớn nhất trong số đó có thể tạo được bằng cách sử dụng tất cả các que diêm của Sơn.

    Yêu cầu: Xác định số nhỏ nhất và lớn nhất mà Sơn có thể tạo ra.

    Dữ liệu vào: Đọc từ file văn bản MATCH.INP có cấu trúc như sau:

    • Dòng đầu tiên là số test K (1<K<=100)
    • K dòng tiếp theo, mỗi test gồm một dòng chứa số nguyên n (2<=n<=100) là số que diêm

    Bài 26: Dãy số được gọi là dãy số đối xứng nếu đọc các phần tử của dãy số này từ trái sang phải hay đọc ngược lại đều được cùng kết quả. Ví dụ: 1, 2, 1 hoặc 1, 2, 2, 1 là các dãy số đối xứng.

    Dãy số P được gọi là dãy số con của dãy số A nếu các phần tử thuộc P có mặt liên tiếp trong dãy số A với thứ tự không đổi. Ví dụ: 2, 1, 3 là dãy số con của 1, 2, 2, 1, 3.

    Cho dãy số tự nhiên A gồm n phần tử a1, a2, a3…an (ai <35000, 5<n<100)

    Yêu cầu: Hãy viết phương trình tìm dãy số P là dãy số con đối xứng dài nhất của dãy số A.

    Dữ liệu vào: Nhập vào số tự nhiên n và n phần tử của dãy số A.

    Kết quả: Xuất ra màn hình kết quả vừa tìm được

    Ví dụ:

    Dữ liệu vào: (nhập từ bàn phím)

    N=5   1 2 2 1

    Kết quả: (xuất ra màn hình)

    A: 1 2 2 1 2

    Bài 27:   Xâu s1 có độ dài m và s2 có độ dài n ( m,n là hai số tự nhiên; n,m<250). Biết rằng s1,s2 chỉ chứa các kí tự ‘A’…’Z’.

    Yêu cầu: Hãy viết phương trình tìm xâu con chung dài nhất của xâu s1 và s2.

    Dữ liệu vào: Nhập từ bàn phím 2 xâu s1 và s2.

    Kết quả: Xuất ra màn hình xâu con chung của 2 xâ s1 và s2.

    Ví dụ:

    Dữ liệu vào: kết quả: ABBA

    S1:ABBABC

    S2:ABABBA

    Bài 28: Cho xâu S có độ dài N (N<100). Xâu S chỉ chứa các k‎ tự số ‘0’…’9’.

    Yêu cầu: Hãy viết chương trình tìm xâu S1 bằng cách hoán vị các k‎ tự số trong xâu S sao cho xâu S1 có giá trị nhỏ nhất lớn hơn S.

    Đữ liệu vào: Cho trong tệp tin so.inp, gồm 1 dòng ghi xâu S.

    Kết quả: Ghi trong tập tin so.out, gồm 1 dòng ghi kết quả vừa tìm được.

    Ví dụ:

    Dữ liệu vào: (So.inp)     Kết quả: (so.out)

    ‘1234’   ‘1324’

    Bài 29: Viết chương tìm ước số chung lớn nhất của hai số nguyên a và b khác 0, với a, b được nhập từ bàn phím.

    Bài 30:  Viết chương trình nhập vào một mảng gồm n phần tử (n<=100). Kiểm tra và in ra màn hình các số là số nguyên tố sắp xếp theo thứ tự tăng dần.

    Bài 31: Cho số tự nhiên N (N<=50). Hãy viết chương trình thực hiện:

    1. Nhập số N, sau đó nhập N số nguyên từ bàn phím. thứ tự của các số gọi là chỉ số.
    2. Hãy tính trong dãy số trên có bào nhiêu số dương chẵn.
    3. Tìm (các) chỉ số của giá trị âm lớn nhất của dãy số nếu có.
    4. Tìm tất cả các dãy con dài nhất các số khác không cùng dấu.

    Bài 32:  Nhập vào từ bàn phím một số N nguyên dương (N<=5000).

    1. Hãy phân tích N thành tổng của hai số nguyên tố (nếu được) và thông báo không được nếu không có phương án nào.
    2. Nếu N thoả mãn câu a, hãy đưa càng nhiều càng tốt các phương án phân tích (2 phương án có cùng các số hạng chỉ coi là một)

    Bài 33:  Cho trước một dãy số bao gồm toàn các số 0 và 1. Dãy này có độ dài nhỏ hơn 255.

    1. Viết chương trình nhập dãy số trên từ bàn phím. Các số được nhập liên tiếp từ bàn phím, quá trình nhập dữ liệu kết thúc nhấn phím <Enter>. Nếu việc nhập dữ liệu sai trên màn hình kết quả “Bạn đã nhập sai, đề nghị nhập lại” và cho phép nhập lại ngay dữ liệu.
    2. Một dãy con đúng của dãy trên được gọi là một dãy con liên tục bất kỳ của dãy trên bao gồm các số hạng giống nhau. Hãy tính độ dài lớn nhất của một dãy con đúng của dãy trên.
    3. Một dãy con đúng bậc 1 của dãy trên được coi là một dãy con liên tục bất kỳ của dãy trên bao gồm toàn các số hạng giống nhau ngoại trừ 1 phần tử. Hãy tính độ dài lớn nhất của một dãy con đúng bậc 1 của dãy trên.

    Bài 34:  Cho số nguyên N trong phạm vi từ 1000 đến 999999. Cần xác định số này có phải là thông tin về một ngày tháng có trong thế kỷ 21 không. (Thế kỷ 21 bắt đầu từ 1 tháng 1 năm 2001 và kết thúc vào ngày 31 tháng 12 năm 3000. Biết rằng 2  chữ số cuối của N là chỉ hai chữ số cuối của năm, các chữ số còn lại (ở đầu) xác định ngày và tháng.

    Ví dụ:

    1111       tương ứng với 1 tháng 1 năm 2011;

    21290     tương ứng với 2 tháng 12 năm 2090 hoặc 21 tháng 2 năm 2090;

    131192 tương ứng với 13 tháng 11 năm 2092;

    32392     Không phải là thông tin về một ngày tháng nào cả;

    311198 Không phải là thông tin về một ngày tháng nào cả;

    29205     Không phải là thông tin về một ngày tháng nào cả;

    Dữ liệu: Nhập vào số N từ bàn phím.

    Kết quả: Đưa ra màn hình các ngày tháng năm tương ứng với N hoặc thông báo là KHONG nếu N không phải là thông tin về một ngày tháng nào cả.

    Ví dụ:

    Giá trị của N Thông báo ra màn hình tương ứng
    1111

    21290

    29205

    1-1-2011

    2-12-2090 HOAC 21-2-2090

    KHONG

    Bài 35:    Cho dãy số nguyên a1, a2,…, an (n <= 1000).

    Hãy tìm cách thực hiện một số ít nhất phép đổi chỗ hai số hạng bất kỳ của dãy để thu được dãy số mà số lẻ đứng ở vị trí lẻ, số chẵn đứng ở vị trí chẵn.

    Dữ liệu: Vào từ file văn bản DAYSO.INP:

    • Dòng đầu tiên chứa số nguyên dương n;
    • Dòng thứ i trong số n dòng tiếp theo chứa số hạng ai của dãy đã cho (-32767 à 32767, i = 1, 2,…, n).

    Kết quả: ghi ra file văn bản DAYSO.OUT:

    • Dòng đầu tiên ghi số lượng phép đổi chỗ cần thực hiện k (qui ước k = -1, nếu không thể biến đổi được dãy đã cho thành dãy thoả 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 hai 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

    2

    3

    4

    6

    5

    1

    5 6

    4

    1

    3

    2

    5

    -1

    Bài 36:  Một nhóm gồm n bạn học sinh của một lớp tham gia một câu lạc bộ tin học vào dịp nghỉ hè. Biết rằng khoảng thời gian mà bạn thứ i có mặt tại câu lạc bộ là [ai, bi] (ai<bi tương ứng là các thời điểm đến và rời khỏi câu lạc bộ). Cô giáo chủ nhiệm lớp muốn tới thăm các bạn trong nhóm này. Hãy giúp cô giáo chủ nhiệm xác định thời điểm đến câu lạc bộ sao cho tại thời điểm đó cô giáo có thể gặp được nhiều bạn trong nhóm nhất.

    Dữ liệu: Vào từ file văn bản MEETING.INP:

    • Dòng đầu tiên ghi số nguyên dương n (n <= 1000);
    • Dòng thứ i trong số n dòng tiếp theo ghi 2 số nguyên không âm ai, bi, i = 1, 2,…, n.

    Kết quả: Ghi ra file văn bản MEETING.OUT:

    • Dòng đầu tiên ghi số nguyên dương k là số lượng bạn đang có mặt ở câu lạc bộ tại thời điểm cô giáo đến;
    • Trong k dòng tiếp theo ghi chỉ số của k bạn có mặt ở câu lạc bộ tại thời điểm cô giáo đến, mỗi dòng ghi một chỉ số của một bạn.

    Ví dụ:

     MEETING.INP MEETING.OUT MEETING.INP MEETING.OUT
    6

    1  2

    2  3

    2  5

    5  7

    6  7

    9 11

    3

    1

    2

    3

    5

    1 2

    3 5

    7 9

    11 15

    17 21

    1

    1

    Bài 37:  Ứng với mỗi số tự nhiên x, ta có số tự nhiên f(x) bằng tổng bình phương các chữ số của x. Từ x ta xây dựng dãy (Xn) như sau:

    X1 = x ; X2 = f(X1) ; X3 = f(X2) ; …; Xi = f(Xi – 1)    với   1 <= I <= n

    Ví dụ:

    x = 12 ta có dãy: 12; 5; 25; 29; 85; 89; 145; 42; 20; 4; 16; 37; 58; 89

    x = 4 ta có dãy: 4; 16; 37; 58; 89; 145; 42; 20; 4

    Viết chương trình nhập vào từ bàn phím số tự nhiên x và in ra màn hình dãy (Xn)

    Dữ liệu vào: Số tự nhiên x.

    Dữ liệu ra: In ra màn hình dãy (Xn)

    Bài 38:  Tạo một dãy gồm n (3 < n < 20) số nguyên nhận các giá trị ngẫu nhiên từ 1 đến 99.  Xuất dãy  và xuất ra vị trí các số nguyên tố của dãy.

    Dữ liệu vào: Số nguyên n có giới hạn theo đề.

    Kết quả ra: Mảng a ngẫu nhiên và vị trí các số nguyên tố trong mảng.

    Ví dụ:

    Dữ liệu vào Dữ liệu ra
    19

     

    So phan tu cua mang: 19

    Mang a la:

    74 98 69 94  5 11 11 50 21 61 89 73 14 19 55 31 71 50  1

    Vi tri cac so nguyen to co trong a la:  5  6  7 10 11 12 14 16 17

    Lưu ý: số 1 không phải là số nguyên tố

    Bài 39:  Viết chương trình in ra màn hình các số từ x đến y là số chẵn và chia hết cho 3. với x, y nhập từ bàn phím? Đếm xem có tất cả bao nhiêu số?

    Dữ liệu vào: Số nguyên x và y (x < y).

    Kết quả ra: Các số chẵn chia hết cho 3 trong phạm vi từ x đến y và đếm có bao nhiêu số.

    Ví dụ:

    Dữ liệu vào Dữ liệu ra
    3

    40

    12  18  24  30  36

    Co tat ca: 6 so

    Các bài từ 40 đến 64 sau đây lấy từ 100 đề Toán Tin (Tin học &#038; Nhà trường)

    Bài 65: Bạn Huy không tập trung tư tưởng trong giờ toán vì vậy thầy giáo cho thêm bài tập về nhà rèn luyện khả năng tập trung tư tưởng và tính cẩn thận chu đáo. Nội dung bài tập là cho n xâu chỉ bao gồm các ký tự la tinh thường và chữ số. Đoạn các ký tự số liên tục tạo thành một số nguyên. Ở mỗi đoạn ký tự số liên tục Huy phải trích ra số lớn nhất có thể, sắp xếp các số nhận được từ các xâu đã cho và đưa ra theo thứ tự không giảm, mỗi số được đưa ra dưới dạng không có các số 0 không có nghĩa.

    Ví dụ, với n = 1 và xâu là 01a2b3456cde478 dãy số cần đưa ra là 1, 2, 478, 3456.

    Yêu cầu: Cho số nguyên n (1 ≤ n ≤ 100) và n xâu, mỗi xâu có độ dài không quá 100. Hãy đưa ra dãy số nhận được đã sắp xếp theo thứ tự không giảm, mỗi số trên một dòng.

    Dữ liệu: Vào từ file văn bản numbers.inp:

    Dòng đầu tiên chứa số nguyên n,

    Mỗi dòng trong n dòng sau chứa một xâu chỉ gồm các ký tự la tinh thường và số.

    Dữ liệu đảm bảo có không quá 500 số được tách ra.

    Kết quả: Đưa ra file văn bản NUMBERS.OUT dãy số nhận được đã sắp xếp theo thứ tự không giảm, mỗi số trên một dòng.

    Ví dụ:

    numbers.inp numbers.out
    4

    43silos0

    zita002

    le2sim

    231233

    0

    2

    2

    43

    231233

    Bài 66: Hãy viết chương trình đổi tờ giấy bạc có mệnh giá n (Việt Nam đồng) ra ba loại giấy bạc có mệnh giá 500, 200, 100 (Việt Nam đồng) sao cho số tờ gấy bạc phải sử dụng là ít nhất (n được nhập từ bàn phím).

    Bài 67: Tuổi của cha hiện nay là b tuổi, tuổi của con là c tuổi (b-c > 0 và b, c là các số nguyên dương). Hãy viết chương trình (với b, c được nhập từ bàn phím) để kiểm tra xem tuổi cha có gấp đôi tuổi con hay không? Nếu đúng thì đưa ra màn hình thông báo “hiện nay tuổi cha gấp đôi tuổi con”; trường hợp ngược lại, hãy tính số năm n (trước đó hoặc sau đó) tuổi cha gấp đôi tuổi con và đưa ra màn hình thông báo “n năm trước đây tuổi cha gấp đôi tuổi con” hay “sau n năm tuổi cha sẽ gấp đôi tuổi con”.

    Bài 68: Hàng tháng, các hộ dân sử dụng điện đều nhận được một hóa đơn thanh toán tiền điện. Giá tiền điện phải trả được tính như sau:

    • 100 số đầu tiên, mỗi số phải trả 550 đồng,
    • Từ số 101 đến số 150, mỗi số phải trả 1100 đồng,
    • Từ số 151 đến số 200, mỗi số phải trả 1470 đồng,
    • Từ số 201 trở đi, mỗi số phải trả 1600 đồng.

    Số tiền điện mà mỗi hộ dân phải trả ở hóa đơn là tổng số tiền điện mà người đó đã sử dụng với 10% thuế VAT.     Hãy viết chương trình tính số tiền điện mà người tiêu dùng phải trả trong tháng với a là số KW điện mà người tiêu dùng đã sử dụng và được nhập từ bàn phím.

    Bài 69: Nhập vào số tự nhiên n (0 < n < 10) và hai mảng số nguyên A, B có n phần tử đại diện cho hai tập hợp theo yêu cầu không có hai phần tử trùng nhau trong cùng một tập hợp. (Do đó, trong quá trình nhập nếu phần tử vừa nhập vào đã có trong mảng thì không bổ sung vào mảng). In ra màn hình tập hợp A, tập hợp B và các phần tử là giao của hai tập hợp A và B.

    Bài 70:

    1. Nhập một dãy số nguyên có n phần tử (0< n <= 100)
    2. Sắp xếp dãy vừa nhập theo thứ tự tăng dần, in ra màn hình dãy đã sắp thứ tự
    3. Tìm trên dãy đã sắp xếp có phần tử x hay không, với x được nhập từ bàn phím.

    Bài 71: Cho đa thức bậc n:

    A = anxn + an-1xn-1+…+ a1x + a0

    Trong đó an, an-1,…a1,a0 là các hệ số nguyên có giá trị tuyệt đối không quá 100.

    Biết rằng phương trình A = 0 nếu có nghiệm nguyên thì nghiệm nguyên đó chỉ có thể là ước số của hệ số a0.

    Yêu cầu: Hãy tìm tất cả các nghiệm nguyên (nếu có) của phương trình A = 0.

    Bài 72: Kỳ thi học sinh giỏi năm học 2008-2009 của tỉnh Bà Rịa-Vũng Tàu có 8 đội tuyển dự thi đến từ các huyện (TX, TP), số thứ tự các huyện được đánh số lần lượt từ 1 đến 8 là Vũng Tàu, Bà Rịa, Tân Thành, Châu Đức, Xuyên Mộc, Đất Đỏ, Long Điền, Côn Đảo. Mỗi thí sinh dự thi có một số báo danh duy nhất (là một số nguyên dương), mỗi đội tuyển của huyện tối đa 90 thí sinh. Sau khi thi xong Sở Giáo dục- Đào tạo tổ chức cho các thí sinh  giao lưu với nhau, Ban tổ chức sắp xếp các thí sinh đứng thành một vòng tròn, để tạo điều kiện cho các thí sinh trong tỉnh được giao lưu với nhau Ban tổ chức yêu cầu các thí sinh cùng huyện không đứng gần nhau, các thí sinh thuộc 2 huyện có số thứ tự liền kề cũng không được đứng gần nhau.

    Yêu cầu: Hãy giúp Ban tổ chức chỉ ra một cách xếp thỏa mãn yêu cầu trên

    Dữ liệu vào: file ‘pupil.inp’

    Gồm có 8 dòng, dòng thứ i chứa các số báo danh của các thí sinh huyện thứ i, các số báo danh cách nhau ít nhất một dấu cách.

    Dữ liệu ra: file ‘pupil.out’

    (Mô tả cách xếp n thí sinh theo yêu cầu trên một vòng tròn, ta có thể mô tả trên một đường thẳng, trong đó thí sinh đầu và thí sinh cuối đứng gần nhau trên vòng tròn)

    Gồm n dòng (n là tổng số thí sinh), mỗi dòng là số báo danh của thí sinh. Trong trường hợp không có cách nào thỏa mãn yêu cầu thì ghi là -1

    Ví dụ

    Pupil.inp Pupil.out
    1 2 3

    4 5 6

    7 8 9

    10 11 12

    13 14 15

    16 17 18

    19 20 21

    22 23

    1

    22

    16

    7

    17

    23

    2

    18

    8

    3

    9

    10

    4

    11

    5

    12

    6

    13

    19

    14

    20

    15

    21

    Bài 73: Nhập vào một số tự nhiên N với (0 < N ≤ 65535). Hãy cho biết chữ số lớn nhất của số tự nhiên vừa nhập. Hãy in đảo ngược số N.

    Ví dụ: N=6548. Chữ số lớn nhất là: 8. Số in ngược là: 8456.

    Bài 74: Nhập vào một số tự nhiên N với (0 < N ≤ 65535), phân tích số vừa nhập thành các thừa số nguyên tố, nếu số vừa nhập là số nguyên tố thì chỉ thông báo ra màn hình đây là số nguyên tố.

    Ví dụ:

    • Nếu số vừa nhập là 300, thì in ra màn hình 300 = 2. 2. 3. 5. 5
    • Nếu số vừa nhập là 307, thì in ra màn hình “307 là số nguyên tố”

    Bài 75: Tìm tất cả các số nguyên dương x, y, z  thỏa mãn phương trình: ax + by + cz = n; trong đó a, b, c, n là các số nguyên dương (a, b, c ≤ 65535; n ≤ 2.147.483.647)

    Yêu cầu kỹ thuật:

    1. Kiểm tra việc nhập dữ liệu thỏa mãn yêu cầu của đề bài. Nếu người sử dụng nhập sai thì thông báo nhập sai và hỏi người dùng có muốn nhập lại hay không, nếu không thì kết thúc chương trình.
    2. Không được dùng quá 2 vòng lặp lồng nhau và điều kiện dừng của mỗi vòng lặp không được vượt quá ngưỡng mà từ đó ta biết chắc chắn phương trình không có nghiệm.
    3. Nếu phương trình có nghiệm thì liệt kê có thứ tự các bộ nghiệm của phương trình theo dạng sau:

    Giả sử phương trình có dạng 15x + 28y + 24z = 454, ta in ra màn hình như sau:

    STT     x          y          x

    1          10        10        1

    2          14        7          2

    Ngược lại không thì thông báo phương trình không có nghiệm.

    Bài 76: Một số có tổng các ước nhỏ hơn nó bằng chính nó được gọi là số hoàn chỉnh.

    Ví dụ: 6 có các ước nhỏ hơn nó là 1, 2, 3. Tổng là 1 + 2 + 3 = 6.

    Viết chương trình xét xem một số n được nhập từ bàn phím có phải là số hoàn chỉnh không.

    Bài 77: Viết chương trình tìm các số hoàn chỉnh nhỏ hơn n (Với n được nhập từ bàn phím).

    Bài 78: Dãy Fibonacy có hai phần tử đầu là 1, 1. Các phần tử sau bằng tổng hai phần tử đứng ngay trước nó:

    1, 1, 2, 3, 5, 8, 13, 21,…

    Viết chương trình in ra dãy Fibonacy có phần tử lớn nhất nhỏ hơn n?

    Bài 79: Viết chương trình nhập n số, xoá số thứ k trong n số vừa nhập. In ra n-1 số còn lại.

    Bài 80: Viết chương trình cho phép nhập một dãy gồm n số nguyên. Nhập thêm một số và chèn thêm vào dãy sau phần tử k.

    Bài 81: Viết chương trình in ra màn hình tam giác Pascal. Ví dụ, với n=4 sẽ in ra hình sau:

    1          1
    
    1          2          1
    
    1          3          3          1
    
    1          4          6          4          1

    Hàng thứ n được xác định từ hàng n-1:

    • Phần tử đầu tiên và phần tử cuối cùng đều bằng 1.
    • Phần tử thứ 2 là tổng của phần tử thứ nhất và thứ 2 của hàng n-1
    • Phần tử thứ k của hàng thứ n là tổng của phần tử thứ k-1 và k của hàng thứ n-1.

    Bài 82: Viết chương trình tính giai thừa của số n (Viết là n!). Với yêu cầu:

    • Nếu người dùng nhập số n < 0 thì yêu cầu nhập lại.
    • Sử dụng chương trình con để tính giai thừa của một số.

    Bài 83: Viết chương trình cho phép cộng hai phân số.

    Bài 84: Nhập vào một số nguyên dương n. Hãy in ra số nguyên tố nhỏ nhất lớn hơn n. VD: Nhập n = 10. Kết quả in ra số 11.

    Bài 85: Tìm các số tự nhiên nhỏ hơn hoặc bằng n mà sau khi làm phép phân tích ra thừa số nguyên tố có nhiều nhân tử nhất. Ví dụ n=9. Các số có nhiều nhân tử nhất sau khi làm phép phân tích là: 8 = 2.2.2

    Viết chương trình cho phép phân tích một số ra thừa số nguyên tố và ghi kết quả dưới dạng tích các lũy thừa. Ví dụ: 300 = 2^2.3.5^2

    Bài 86: Mọi số tự nhiên đều có thể viết được dưới dạng tổng của hai số nguyên tố. Viết chương trình thực hiện tách một số tự nhiên thành tổng của hai số nguyên tố.

    Bài 87: Hai số tự nhiên A, B được coi là hữu nghị nếu như số này bằng tổng các ước số của số kia và ngược lại. Lập trình tìm và in ra màn hình các cặp số hữu nghị trong phạm vi từ 1 đến 10000. (Lưu ý, số 1 được coi là ước số của mọi số còn mỗi số không được coi là ước số của chính nó).

    Bài 88: Cho dãy số gồm n số. Tìm dãy con lớn nhất các phần tử tăng (giảm) dần.

    Bài 89: Cho dãy số gồm n số. Tìm dãy con lớn nhất các phần tử có cùng dấu, (đan dấu).

    Bài 90: Cho dãy gồm n số. Tìm dãy con lớn nhất đơn điệu (liên tục tăng, giảm hoặc giảm, tăng).

    Bài 91:  Cho dãy số gồm n số nguyên. Tìm dãy con có tổng lớn nhất

    Hướng dẫn. Sử dụng kỹ thuật vét cạn các dãy con, dùng hàm tính tổng dãy con để kiểm tra.

    Bài 92: Gọi abcd là một số có 4 chữ số. Hãy lập chương trình tìm tất cả các số có 4 chữ số thỏa mãn biểu thức: abcd=(ab + cd)^2. Ví dụ 2025=(20 + 25)^2.

    Bài 93:  Viết chương trình cho nhập hai số tự nhiên Nk. Hãy cho biết chữ số thứ k tính từ trái sang phải trong số N là chữ số nào? Nếu k lớn hơn độ dài của N hoặc k bằng 0 thì thông báo không tìm được.

    Bài 94:  Một số được gọi là số bậc thang nếu biểu diễn thập phân của nó có nhiều hơn một chữ số đồng thời theo chiều từ trái qua phải, chữ số đứng sau không nhỏ hơn chữ số đứng trước. Viết chương trình in ra các số bậc thang trong đoạn [n1, n2] với n1, n2 được nhập từ bàn phím.

    Bài 95: Viết chương trình cho phép đổi một số từ cơ số 10 sang cơ số bất kỳ.

    Thuật toán:

    • Dùng mảng CS để lưu các chữ số.
    • Lặp khi n <> việc: Chia n cho s lấy phần dư. Lấy phần dư làm chỉ số để lấy và lưu chữ số. Gán n = n div s.

    Chú ý chữ số lấy sau sẽ nằm trước.

    Bài 96: Viết chương trình cho phép đổi một số từ cơ số bất kỳ sang cơ số 10.

    Bài 97: Năm 1973, nhà Toán học Neil Sloan đưa ra khái niệm độ bền của một số nguyên không âm N như sau:

    • Nếu N có một chữ số thì độ bền của N bằng 0.
    • Nếu N có từ hai chữ số trở lên thì độ bền của N bằng độ bền của số nguyên là tích các chữ số của N cộng 1.

    Cho N từ 0  đến 2.000.000.000, tìm số bé hơn N có độ bền lớn nhất.

    Ví dụ

    Persist.inp Persist.out Giải thích
    100 77 Doben(77)=Doben(49)+1=Doben(36)+1+1=Doben(18)+1+1+1=Doben(8)+1+1+1+1=0+1+1+1+1=4

    Hướng dẫn.

    • Để tìm độ bền một số cần một hàm TICH(n) tính tích các chữ số của n.
    • Cho d = 0. Lặp lại điều kiện n >9 việc tăng d lên 1 thay n = TICH(n).
  • Đề thi đầu vào của công ty MDC

    Đề thi đầu vào của công ty MDC

    Đề thi đầu vào của công ty MDC

    Công ty cổ phần Tập đoàn MDC (MDC Group) hoạt động trong các lĩnh vực công nghệ thông tin, sản xuất, y tế, phòng cháy – chữa cháy, phân phối & bán lẻ.

    Trong các công ty liên kết với viện CNTT&TT của BKHN thì MDC chọn cách phỏng vấn ứng viên bằng một bài test nhỏ. Thường khi các công ty test ứng viên bằng bài test thì sẽ là thuật toán là chủ yếu nha, là những thứ như cấu trúc dữ liệu & thuật toán, thuật toán ứng dụng, những kiến thức về đồ thị,…

    Xem thêm KINH NGHIỆM PHỎNG VẤN FLUTTER

    Vệ tinh

    Tập đoàn viễn thông đa quốc gia UltraCom hiện sở hữu một hệ thống truyền tin gồm N trung tâm truyền nhận dữ liệu (gọi tắt là trung tâm) nằm rải rác khắp địa cầu (các trung tâm này được đánh số từ 1 đến N) và M vệ tinh (gọi tắt là vệ tinh) cũng được phân bố đều khắp trên bầu trời quanh địa cầu (các vệ tinh này được đánh số từ 1 đến M).

    Mỗi trung tâm i đều có thể thiết lập kết nối trực tiếp (để khai thác) với mỗi vệ tinh j với chi phí xác định Cij nào đó.

    Hai trung tâm được xem là thông băng với nhau nếu chúng cùng được kết nối với một vệ tinh hoặc chúng cùng thông băng với một số trung tâm khác.

    Toàn hệ thống của UltraCom đương nhiên vốn là thông băng hoàn toàn, tức là bất kỳ hai trung tâm nào cũng đều thông băng với nhau.

    Một sự cố bí ẩn vừa diễn ra trong thời gian gần đây đã khiến một số kết nối bị hư hỏng hoàn toàn và hệ thống của UltraCom bị rơi vào tình trạng không thông băng hoàn toàn được, đặt ra nhiệm vụ cấp bách cho UltraCom phải khẩn trương khắc phục hậu quả này.

    Sau sự cố, bộ phận phụ trách kỹ thuật của UltraCom đã tiến hành khảo sát toàn hệ thống và nhận thấy rằng:

    1. Mỗi trung tâm đều vẫn còn đang kết nối bình thường với một số các vệ tinh đồng thời mỗi vệ tinh đều còn đang được kết nối bởi một số trung tâm nào đó.
    2. Một số kết nối vừa bị hỏng sẽ không thuộc diện xem xét khắc phục nữa, do chi phí quá lớn.
    3. Hoàn toàn có phương án khả thi để khắc phục hệ thống thông băng hoàn toàn.

    Để tiết kiệm chi phí tại thời điểm nhạy cảm của nền kinh tế toàn cầu, ban lãnh đạo tập đoàn quyết định sẽ chỉ thiết lập lại một số kết nối đã bị hư hỏng sao cho tổng chi phí khắc phục là nhỏ nhất có thể.

    Yêu cầu: Xác lập phương án cụ thể và tổng chi phí nhỏ nhất để UltraCom khắc phục sự cố

    Dữ liệu vào: Cho trong file văn bản REPAIR.INP, gồm:

    • Dòng đầu ghi tuần tự 2 số nguyên dương N, M (2 ≤ M, N ≤ 1000)
    • Dòng thứ i trong N dòng tiếp theo ghi M số nguyên Ci1, …, CiM (-1 ≤ Cij ≤10000; i = 1, …, N; j = 1, 2,…, M) với ý nghĩa: Cij là chi phí để kết nối trung tâm i với vệ tinh j cùng sự lưu ý đặc biệt: Cij = 0 nếu trung tâm i vẫn đang kết nối bình thường được với vệ tinh j, Cij = -1 nếu bỏ qua việc tái lập sự kết nối giữa trung tâm i với vệ tinh j (do chi phí quá lớn).
    • Tất cảc các số nguyên trên cùng dòng đều cách nhau bởi khoảng trống. Dữ liệu luôn đảm bảo tính đúng đắn để có lời giải, tức là luôn có phương án để UltraCom khắc phục sự cố.

    Kết quả: Ghi ra file văn bản REPAIR.OUT các thông tin sau:

    • Dòng đầu ghi một số nguyên, là tổng chi phí nhỏ nhất tìm được. Thông tin này chiếm 50% số điểm của test.
    • Dòng thứ 2 ghi số nguyên dương K, với K là số kết nối cần khắc phục. Thông tin này chiếm 25% số điểm của test.
    • K dòng tiếp theo, mỗi dòng ghi hai số nguyên c, s (cách nhau bởi khoảng trống) cho biết cần tái lập kết nối giữa trung tâm c với vệ tinh s. Nếu có nhiều kết quả (phương án), chỉ cần chỉ ra một trong chúng. Thông tin trên K dòng này chiếm 25% số điểm của test.

    Ví dụ:

    REPAIR.INP
    4 3
    0 -1 5
    0 4 4
    -1 0 -1
    1 2 0
    
    REPAIR.OUT
    3 2
    4 1
    4 2
    
    REPAIR.INP
    4 4
    0 -1 5 3
    -1 4 5 -1
    -1 0 -1 0
    6 7 0 -1
    

    Ràng buộc:

    • 60% số test ứng với 60% số điểm của bài ứng với N, M ≤ 200.
    • Giới hạn thời gian cho mỗi test: 01 giây.

    Hướng dẫn: Sử dụng thuật toán tham lam, xác định tập lớn nhất các trung tâm đang thông băng (S) , sắp xếp các kết nối theo thứ tự chi phí từ nhỏ đến lớn, sau đó thực hiện kết nối mới (C) vào tập với điều kiện trung tâm X chưa nằm trong tập (S).

    Cây và Rừng

    Một cấu trúc dạng cây được tổ chức trong CSDL quan hệ dưới dạng các dòng của bảng như sau.

    Đề thi đầu vào của công ty MDC 6

    Trong đó, node gốc trong cây sẽ có mã node cha là 0. Có thể có nhiều cây khác nhau trong rừng. Số dòng tối đa có thể lên đến 1.000.000

    Yêu cầu:

    1. Đọc từ tệp tin tree.txt các node của cây vào bộ nhớ, tệp tin gồm nhiều dòng, mỗi dòng là một node chứa 3 trường thông tin: Mã của node, mã node cha, tên của node.
    2. Nhập vào một cặp mã node XY, trả lời xem X có phải là node cha (ông, cụ…) của Y hay không. Hiển thị ra màn hình mối quan hệ của XY (ví dụ: X=>A=>B=>Y)
    3. Nhập vào một mã node X, in ra màn hình tất cả các node con, cháu, chắt….của X (bao gồm mã node, tên node, mỗi cái trên một dòng).
    4. Hiện thời gian thực hiện thuật toán cho ý 2 và 3, tính theo ms (milisecond)

    Đề thi tham khảo từ https://www.tailieubkhn.com/2021/06/de-thi-dau-vao-mdc.html

  • Quy hoạch động là gì?

    Quy hoạch động là gì?

    Quy hoạch động là gì?

    Quy hoạch động (Dynamic Programming) là kĩ thuật được được dùng khi có một công thức truy hồi và một (hoặc một vài) trạng thái bắt đầu. Một bài toán được tính bởi các bài toán nhỏ hơn đã tìm ra trước đó, một kĩ thuật giải quyết các bài toán khi có thể giải quyết bài toán đó bằng cách sử dụng lại các bài toán nhỏ hơn đã được giải quyết và lưu lại kết quả.

    1. Quy hoạch động là gì?

    Theo thầy Lê Minh Hoàng thì

    Các thuật toán đệ quy có ưu điểm dễ cài đặt, tuy nhiên do bản chất của quá trình đệ quy, các chương trình này thường kéo theo những đòi hỏi lớn về không gian bộ nhớ và một khối lượng tính toán khổng lồ. Quy hoạch động (Dynamic programming) là một kỹ thuật nhằm đơn giản hóa việc tính toán các công thức truy hồi bằng cách lưu trữ toàn bộ hay một phần kết quả tính toán tại mỗi bước với mục đích sử dụng lại.

    Dynamic Programming = Solving Recurrence + Memoization

    Hiểu đơn giản, QUY HOẠCH ĐỘNG = GIẢI QUYẾT TRUY HỒI + GHI NHỚ KẾT QUẢ. Quy hoạch động có độ phức tạp đa thức nên sẽ chạy nhanh hơn quay lui và vét cạn.

    2. Khi nào thì dùng Quy hoạch động?

    Không có một quy tắc chung nào để cho biết một bài toán có giải được bằng quy hoạch động hay không. Tuy nhiên, nếu bài toán có hai tính chất sau thì bạn có thể nghĩ tới quy hoạch động:

    • Có một hệ thức truy hồi. Tức là, bài toán lớn có thể giải quyết dựa vào các bài toán con lồng nhau. Chẳng hạn số Fibonacci f(n) được tính dựa vào hai số thứ f(n-1)f(n-2).
    • Một hoặc nhiều bài toán con đã được giải quyết (biết trạng thái). Ví dụ đối với bài toán tìm số Fibonacci thì số f(0)f(1) là đã biết trước.

    bài toán quy hoạch động

    Nghe có vẻ giống như đệ quy, một bài toán lớn được chia nhỏ thành các bài toán con lồng nhau. Nhưng, phương pháp quy hoạch động sẽ lưu kết quả của bài toán con này, và khi được gọi, nó sẽ không cần phải tính lại, do đó làm giảm thời gian tính toán.

    Ví dụ, đối với bài toán tìm số Fibonacci thứ n, nếu sử dụng đệ quy đơn thuần, chúng ta rất nhiều bài toán con sẽ được tính đi tính lại, điển hình là các số fib(0) và fib(1).

    def fib(n):
        if n <= 1:
            return n
        return fib(n -1) + fib(n - 2)

    Nếu sử dụng quy hoạch động, mỗi bài toán con fib(i) sẽ được lưu lại trước khi tính những bài toán con lớn hơn. Nhờ đó, mà việc tính toán giảm đi đáng kể, mỗi bài toán con chỉ cần tính đúng một lần.

    def fib(n):
        dp = [0] * (n + 1)
        dp[1] = 1
        for i in range(2, n + 1):
            dp[i] = dp[i - 1] + dp[i - 2]
        return dp[n]

    Như vậy, vấn đề mấu chốt ở đây là gì?

    Đệ quy chỉ đơn giản là gọi lại chính nó. Quy hoạch động là một cách để giải quyết các vấn đề có cấu trúc cụ thể (cấu trúc con tối ưu) trong đó một vấn đề có thể được chia thành các vấn đề con tương tự như bài toán ban đầu.

    Ghi nhớ kết quả là một cách để tối ưu hóa các thuật toán quy hoạch động dựa trên đệ quy. Và, chúng ta không phải giải quyết bài toán con một lần nữa nếu chúng đã được giải quyết.

    Rõ ràng người ta có thể gọi đệ quy để giải quyết một bài toán quy hoạch động, nhưng nó không cần thiết. Người ta có thể giải một bài toán quy hoạch động mà không cần đệ quy (chẳng hạn trong bài tính số Fibonacci bằng quy hoạch động ở trên, chúng ta thấy không có lời gọi đệ quy nào cả).

    3. Một số ví dụ về Quy hoạch động

    Phân tích số nguyên dương

    Cho số tự nhiên n 100. Hãy cho biết có bao nhiêu cách phân tích số n thành tổng của dãy các số nguyên dương, các cách phân tích là hoán vị của nhau chỉ tính là một cách. (Bài toán này được viết lại dựa theo sách của thầy Lê Minh Hoàng).

    Ví dụ: n = 5 có 7 cách phân tích:

    1. 5 = 1 + 1 + 1 + 1 + 1
    2. 5 = 1 + 1 + 1 + 2
    3. 5 = 1 + 1 + 3
    4. 5 = 1 + 2 + 2
    5. 5 = 1 + 4
    6. 5 = 2 + 3
    7. 5 = 5

    Lưu ý: n = 0 vẫn coi là có 1 cách phân tích thành tổng các số nguyên dương, là tổng của dãy rỗng.

    Để giải bài toán này, chúng ta có thể dùng phương pháp liệt kê tất cả các cách phân tích và đếm số cấu hình. Tuy nhiên, khi số cách phân tích tương đối lớn, phương pháp liệt kê tỏ ra khá chậm. Chẳng hạn với n = 100190569292 cách phân tích.

    Nhận xét:

    Nếu gọi F[m, v] là số cách phân tích số v thành tổng các số nguyên dương nhỏ hơn hoặc bằng m thì khi đó, các cách phân tích số v thành tổng các số nguyên dương nhỏ hơn hoặc bằng m có thể chia làm hai loại:

    • Loại 1: Không chứa số m trong phép phân tích, khi đó số cách phân tích loại này chính là số cách phân tích số v thành tổng các số nguyên dương nhỏ hơn m, tức là số cách phân tích số v thành tổng các số nguyên dương nhỏ hơn hoặc bằng m - 1 và bằng F[m-1, v].
    • Loại 2: Có chứa ít nhất một số m trong phép phân tích. Khi đó nếu trong các cách phân tích loại này ta bỏ đi số m đó thì ta sẽ được các cách phân tích số v - m thành tổng các số nguyên dương nhỏ hơn hoặc bằng m (Lưu ý, điều này chỉ đúng khi không tính lặp lại các hoán vị của một cách). Có nghĩa là về mặt số lượng, số các cách phân tích loại này bằng F[m, v - m].

    Trong trường hợp m > v thì rõ ràng chỉ có các cách phân tích loại 1, còn trong trường hợp m ≤ v thì sẽ có cả các cách phân tích loại 1 và loại 2. Vì thế, công thức truy hồi là: $$F[m,v]=\begin{cases} F[m-1,v] &\text{ nếu } m>v\\ F[m-1,v] +F[m,v-m]&\text{ nếu } m \leqslant v \end{cases}$$

    Tìm số lượng đồng xu

    Cho $N$ đồng xu, giá trị của mỗi đồng là $V_0,V_1,…,V_{N−1}$, và số $S$. Tìm số lượng đồng xu nhỏ nhất để tổng giá trị của chúng bằng $S$ (số lượng đồng xu không giới hạn).

    Với bài toán này, chúng ta cần xây dựng và giải các bài toán con lồng (gối) nhau. Với ví dụ của chúng ta, mỗi bài toán con dp(P) với P<= S là bài toán tìm số đồng xu nhỏ nhất để khối lượng của chúng là P. và dp(P) = k chính là số lượng đồng xu nhỏ nhất đó.

    Chúng ta sẽ áp dụng phương pháp quy hoạch động bằng cách bắt đầu từ bài toán con dp(0) sau đó tiếp tục với các bài toán con lớn hơn. Lời giải của các bài toán con sẽ được xây dựng lần lượt cho đến chúng ta xây dựng đến bài toán dp(S) và đó chính là kết quả của bài toán lớn. Một điều cần lưu ý với kỹ thuật này là bài toán con tiếp theo sẽ không thể giải được nếu chúng ta chưa giải bài toán con trước đó.

    Cuối cùng là phần khó nhất của mọi bài toán quy hoạch động, đó là trả lời câu hỏi: cấu trúc con tối ưu của bài toán này ở đâu. Hay nói một cách khác, làm thế nào để từ những bài toán nhỏ hơn có thể tổ hợp ra lời giải cho bài toán lớn. Với vị dụ kinh điển này, mọi thứ sẽ tương đối đơn giản, nhưng với những bài toán phức tạp hơn, chúng ta cần suy nghĩ và tính toán nhiều hơn.

    Quay trở lại với bài toán của chúng ta. Giả sử P là tổng khối lượng của các đồng xu nặng lần lượt là V1, V2, ..., Vj. Để có được khối lượng P, chúng ta cần thêm vài đúng 1 đồng xu nặng U vào khối lượng Q sao cho Q + U = P. Tất nhiên, bài toán con dp(Q) chúng ta đã có lời giải nên chúng ta sẽ biết được cần bao nhiêu đồng xu cho dp(P). Và vì có nhiều đồng xu U (nhiều nhưng hữu hạn) nên chúng ta có thể cần đến nhiều bài toán con trước đó, và dp(p) là giá trị nhỏ nhất sau khi tổng hợp những bài toán con đó.

    Ví dụ với n = 3, S = 11, W = [1, 3, 5].

    • Bắt đầu với bài toán con 0 ta có dp(0) = 0
    • Với bài toán con 1, có 1 đồng xu (nặng 1) có thể thêm vào từ 0 đồng xu nào cả. Vậy dp(1) = dp(0) + 1 = 1.
    • Với bài toán con 2, cũng chỉ có 1 đồng xu (nặng 1) có thể thêm vào từ 1 đồng xu. Vậy dp(2) = dp(1) + 1 = 2.
    • Với bài toán con 3, chúng ta có thể thêm 1 đồng xu 3 vào 0 đồng xu hoặc thêm 1 đồng xu 1 vào 2 đồng xu. Rõ ràng là cách đầu tiên cho kết quả nhỏ hơn. Vậy dp(3) = min(dp(2) + 1, dp(0) + 1) = min(3, 1) = 1
    • Cứ tiếp tục như vậy cho đến bài toán S chính là đáp án chúng ta cần tìm.

    Về mặt cài đặt, quy hoạch động thường lưu kết quả vào một mảng. Trong ví dụ của chúng ta, mảng dp[0..S] sẽ lưu kết quả cho từng bài toán con. Nói cách khác, dp[P] = k nghĩa là cần ít nhất k đồng xu để có khối lượng là P Toàn bộ mảng này sẽ được tính bằng vòng lặp. Đoạn code sau mô tả toàn bộ quá trình này.

    n, S = map(int, input().split())
    w = list(map(int, input().split()))
    dp = [0] * (S + 1)
    dp[0] = 0
    
    for P in range(1, S + 1):
        dp[P] = min(dp[P - x] for x in w if x <= P) + 1
    
    print(dp)
    print(dp[S])
    
    # Nếu đầu vào như sau: n = 3, S = 11, w = [1, 3, 5]
    # Thì bảng lời giải cho các bài toán con sẽ lần lượt như sau:
    # P = 0 |1 |2 |3 |4 |5 |6 |7 |8 |9 |10|11
    # ------+--+--+--+--+--+--+--+--+--+--+--
    # k = 0 |1 |2 |1 |2 |1 |2 |3 |2 |3 |2 |3

    Bạn có thể tham khảo thêm MỘT SỐ BÀI TOÁN QUY HOẠCH ĐỘNG ĐIỂN HÌNH

  • MỘT SỐ BÀI TOÁN QUY HOẠCH ĐỘNG ĐIỂN HÌNH

    MỘT SỐ BÀI TOÁN QUY HOẠCH ĐỘNG ĐIỂN HÌNH

    MỘT SỐ BÀI TOÁN QUY HOẠCH ĐỘNG ĐIỂN HÌNH

    Quy hoạch động là gì?

    Theo wiki, quy hoạch động (tiếng Anh: dynamic programming) là một phương pháp giảm thời gian chạy của các thuật toán thể hiện các tính chất của các bài toán con gối nhau (overlapping subproblem) và cấu trúc con tối ưu (optimal substructure).

    Cấu trúc con tối ưu có nghĩa là các lời giải tối ưu cho các bài toán con có thể được sử dụng để tìm các lời giải tối ưu cho bài toán toàn cục. Ví dụ, đường đi ngắn nhất tới một đỉnh trong một đồ thị có thể được tìm thấy bằng cách: trước hết tính đường đi ngắn nhất tới đích từ tất cả các đỉnh kề nó, rồi dùng kết quả này để chọn đường đi toàn cục tốt nhất, như trong hình sau.

    MỘT SỐ BÀI TOÁN QUY HOẠCH ĐỘNG ĐIỂN HÌNH 7

    Nói chung, ta có thể giải một bài toán với cấu trúc con tối ưu bằng một quy trình ba bước:

    1. Chia bài toán thành các bài toán con nhỏ hơn.
    2. Giải các bài toán này một cách tối ưu bằng cách sử dụng đệ quy quy trình ba bước này.
    3. Sử dụng các kết quả tối ưu đó để xây dựng một lời giải tối ưu cho bài toán ban đầu.

    Các bài toán con được giải bằng cách chia chúng thành các bài toán nhỏ hơn, và cứ tiếp tục như thế, cho đến khi ta đến được trường hợp đơn giản dễ tìm lời giải.

    bài toán quy hoạch động

    Nói rằng một bài toán có các bài toán con trùng nhau có nghĩa là mỗi bài toán con đó được sử dụng để giải nhiều bài toán lớn hơn khác nhau. Ví dụ, trong dãy Fibonacci, F3 = F1 + F2 và F4 = F2 + F3 — khi tính mỗi số đều phải tính F2. Vì tính F5 cần đến cả F3 và F4, một cách tính F5 một cách ngây thơ có thể sẽ phải tính F2 hai lần hoặc nhiều hơn. Điều này áp dụng mỗi khi có mặt các bài toán con gối nhau: một cách tiếp cận ngây thơ có thể tốn thời gian tính toán lại lời giải tối ưu cho các bài toán con mà nó đã giải.

    Xem thêm: Giải thuật Đệ quy là gì?

    Dãy con đơn điệu dài nhất

    1. Mô hình

    Cho dãy a_1, a_2,… a_n. Hãy tìm một dãy con tăng có nhiều phần tử nhất của nó.

    Đặc trưng:

    • Các phần tử trong dãy kết quả chỉ xuất hiện một lần. Vì vậy phương pháp làm là ta sẽ dùng vòng lặp for duyệt qua các phần tử a_i trong dãy, khác với các bài toán của mô hình 4 (đặc trưng là bài toán đổi tiền), các phần tử trong dãy có thể được chọn nhiều lần nên ta thực hiện bằng phương pháp cho giá trị cần quy đổi tăng dần từng đơn vị.
    • Thứ tự của các phần tử được chọn phải được giữ nguyên so với dãy ban đầu.

    Đặc trưng này có thể mất đi trong một số bài toán khác tùy vào yêu cầu cụ thể, chẳng hạn bài Tam giác bao nhau.

    2. Công thức quy hoạch động

    Hàm mục tiêu: f = độ dài dãy con.

    Vì độ dài dãy con chỉ phụ thuộc vào một yếu tố là dãy ban đầu nên bảng phương án là bảng một chiều. Gọi L(i)độ dài dãy con tăng dài nhất, các phần tử lấy trong miền từ a_1đến a_i và phần tử cuối cùng là a_i.

    Nhận xét với cách làm này ta đã chia bài toán lớn (dãy con của n số) thành các bài toán con cùng kiểu có kích thước nhỏ hơn (dãy con của dãy i số). Vấn đề là công thức truy hồi để phối hợp kết quả của các bài toán con.

    Ta có công thức QHĐ để tính L(i) như sau:

    • L(1) = 1. (Hiển nhiên)
    • L(i) = max(1, L(j)+1) với mọi phần tử j thỏa mãn 0<j<ia_j <= a_i.

    Tính L(i): Phần tử đang được xét là a_i. Ta tìm đến phần tử a_j < a_i L(j) lớn nhất. Khi đó nếu bổ sung a_i vào sau dãy con ...a_j ta sẽ được dãy con tăng dần dài nhất xét từ a_1đến a_i.

    3. Cài đặt

    Bảng phương án là một mảng một chiều L để lưu trữ các giá trị của hàm QHĐ L(i). Đoạn chương trình tính các giá trị của mảng L như sau:

    for i: = 1 to n do begin
    L[i]: = 1;
    for j:=1 to i–1 do
    if (a[j]<=a[i]) and (L[i]<L[j]+1) then
    L[i]:=L[j]+1;
    end;

    Như vậy chi phí không gian của bài toán là O(n), chi phí thời gian là O(n2). Có một phương pháp cài đặt tốt hơn so với phương pháp trên, cho chi phí thời gian là O(n log(n)).

    4. Một số bài toán khác

    Bài toán dãy con đơn điệu tăng dài nhất có biến thể đơn giản nhất là bài toán dãy con đơn điệu giảm dài nhất, tuy nhiên chúng ta có thể coi chúng như là một. Sau đây là một số bài toán khác.

    a) Bố trí phòng họp (mất tính thứ tự so với dãy ban đầu)

    n cuộc họp, cuộc họp thứ i bắt đầu vào thời điểm a_i và kết thúc ở thời điểm b_i. Do chỉ có một phòng hội thảo nên hai cuộc họp bất kì sẽ được cùng bố trí phục vụ nếu khoảng thời gian làm việc của chúng chỉ giao nhau tại đầu mút. Hãy bố trí phòng họp để phục vụ được nhiều cuộc họp nhất.

    Hướng dẫn: Sắp xếp các cuộc họp tăng dần theo thời điểm kết thúc b_i. Thế thì cuộc họp i sẽ bố trí được sau cuộc họp j nếu và chỉ nếu j<i và b_j <= a_i. Yêu cầu bố trí được nhiều cuộc họp nhất có thể đưa về việc tìm dãy các cuộc họp dài nhất thoả mãn điều kiện trên.

    b) Cho thuê máy

    Trung tâm tính toán hiệu năng cao nhận được đơn đặt hàng của n khách hàng. Khách hàng i muốn sử dụng máy trong khoảng thời gian từ a_i đến b_i và trả tiền thuê là c_i. Hãy bố trí lịch thuê máy để tổng số tiền thu được là lớn nhất mà thời gian sử dụng máy của hai khách hàng bất kì được phục vụ đều không giao nhau (cả trung tâm chỉ có một máy cho thuê).

    Hướng dẫn: Tương tự như bài toán a), nếu sắp xếp các đơn đặt hàng theo thời điểm kết thúc, ta sẽ đưa được bài toán b) về bài toán tìm dãy con có tổng lớn nhất. Bài toán này là biến thể của bài toán tìm dãy con tăng dài nhất, ta có thể cài đặt bằng đoạn chương trình như sau:

    for i:=1 to n do begin
    L[i]:=c[i];
    for j:=1 to i–1 do
    if (b[j]<=a[i]) and (L[i]<L[j]+c[i]) then
    L[i]:=L[j]+c[i];
    end;

    c) Dãy tam giác bao nhau

    Cho n tam giác trên mặt phẳng. Tam giác i bao tam giác j nếu ba đỉnh của tam giác j đều nằm trong tam giác i (có thể nằm trên cạnh). Hãy tìm dãy tam giác bao nhau có nhiều tam giác nhất.

    Hướng dẫn: Sắp xếp các tam giác tăng dần về diện tích. Khi đó tam giác i sẽ bao tam giác j nếu j<i và ba đỉnh của j nằm trong i. Từ đó có thể đưa về bài toán tìm dãy “tăng” dài nhất.

    Việc kiểm tra điểm M có nằm trong tam giác ABC không có thể dựa trên phương pháp tính diện tích: Điểm M nằm trong nếu S(ABC) = S(ABM) + S(ACM) + S(BCM).

    Bài toán có một số biến thể khác như tìm dãy hình tam giác, hình chữ nhật… bao nhau có tổng diện tích lớn nhất.

    d) Dãy số WAVIO

    Dãy số Wavio là dãy số nguyên thỏa mãn các tính chất, các phần tử đầu sắp xếp thành một dãy tăng dần đến một phần tử đỉnh sau đó giảm dần. Ví dụ dãy số 1 2 3 4 5 2 1 là dãy Wavio độ dài 7.

    Cho một dãy gồm N số nguyên, hãy chỉ ra một dãy con WAVIO có độ dài lớn nhất trích ra từ dãy đó.

    Hướng dẫn: L1[i] là mảng ghi độ dài lớn nhất của 1 dãy con tăng dần trích ra từ dãy N phần tử kể từ phần tử 1 đến phần tử ai. L2[i]: mảng ghi độ dài lớn nhất của dãy con giảm dần trích ra từ dãy N phần tử kể từ phần tử aN đến ai. Ta tìm phần tử j trong 2 mảng L1, L2 thỏa mãn L1[j]+L2[j] lớn nhất.

    e) Xếp các khối đá

    Cho N khối đá (N≤5000). Các khối đá đều có dạng hình hộp chữ nhật và được đặc trưng bới 3 kích thước: dài, rộng, cao. Một cách xây dựng tháp là một cách đặt một số các khối đá trong các khối đá đã cho chồng lên nhau theo quy tắc:

    • Chiều cao mỗi khối đá là kích thước nhỏ nhất trong 3 kích thước.
    • Các mép của khối đá được đặt song song với nhau sao cho không có phần nào của khối trên nằm chìa ra ngoài khối dưới.

    a) Hãy chỉ ra cách để xây dựng được một cái tháp sao cho số khối đá được dùng là nhiều nhất.

    b) Hãy chỉ ra cách để xây dựng được một cái tháp sao cho chiều cao của cái tháp là cao nhất.

    Dữ liệu vào TOWER.INP có cấu trúc như sau:

    • Dòng đầu là số N.
    • N dòng sau dòng i ghi 3 số nguyên ≤ 255 là 3 kích thước của khối đá i.

    Dữ liệu ra: TOWER1.OUT, TOWER2.OUT ghi theo quy cách:

    • Dòng đầu ghi số các khối đá được chọn theo thứ tự dùng để xây tháp từ chân lên đỉnh.
    • Các dòng sau ghi các khối được chọn, mỗi khối đá ghi 4 số T, D, R, C trong đó T là số thứ tự của mỗi khối đá. D, R, C là kích thước của khối đá tương ứng.

    II. Vali (B)

    1. Mô hình

    Có n đồ vật, vật thứ i có trọng lượng a[i] và giá trị b[i]. Hãy chọn ra một số các đồ vật, mỗi vật một cái để xếp vào 1 vali có trọng lượng tối đa W sao cho tổng giá trị của vali là lớn nhất.

    2. Công thức

    Hàm mục tiêu: f: tổng giá trị của vali.

    Nhận xét: giá trị của vali phụ thuộc vào 2 yếu tố: có bao nhiêu vật đang được xét và trọng lượng của các vật. Do đó bảng phương án sẽ là bảng 2 chiều.

    L[i,j]: tổng giá trị lớn nhất của vali khi xét từ vật 1..vật i và trọng lượng của vali chưa vượt quá j. Chú ý rằng khi xét đến L[i,j] thì các giá trị trên bảng phương án đều đã được tối ưu.

    Tính L[i,j]: vật đang xét là ai với trọng lượng của vali không được quá j. Có 2 khả năng xảy ra:

    • Nếu chọn aiđưa vào vali, trọng lượng vali trước đó phải ≤ j-a[i]. Vì mỗi vật chỉ được chọn 1 lần nên giá trị lớn nhất của vali lúc đó là L[i-1,j-a[i]) + b[i]
    • Nếu không chọn ai , trọng lượng của vali là như cũ (như lúc trước khi chọn ai ): L[i-1,j].

    Tóm lại ta có L[i,j]=max(L(i-1,j-a[i]) + b[i], L[i-1,j]).

    3. Cài đặt

    For i:=1 to n do
    For j:=1 to W do
    If b[i]<=j then
    L[i,j]:=max(L(i-1,j-a[i]) + b[i], L[i-1,j])
    else L[i,j]:=L[i-1,j];

    4. Một số bài toán khác

    a) Dãy con có tổng bằng S

    Cho dãy a1,a2,..an. Tìm một dãy con của dãy đó có tổng bằng S.

    Hướng dẫn
    Đặt L[i,t)=1 nếu có thể tạo ra tổng t từ một dãy con của dãy gồm các phần tử a1,a2,..ai. Ngược lại thì L[i,t)=0. Nếu L[n,S)=1 thì đáp án của bài toán trên là “có”.

    Ta có thể tính L[i,t] theo công thức: L[i,t]=1 nếu L[i–1,t]=1 hoặc L[i–1,t–a[i]]=1.

    Cài đặt

    Nếu áp dụng luôn công thức trên thì ta cần dùng bảng phương án hai chiều. Ta có thể nhận xét rằng để tính dòng thứ i, ta chỉ cần dòng i–1. Bảng phương án khi đó chỉ cần 1 mảng 1 chiều L[0..S] và được tính như sau:

    L[t]:=0; L[0]:=1;
    for i: = 1 to n do
    for t: = S downto a[i] do
    if (L[t]=0) and (L[t–a[i]]=1) then L[t]:=1;

    Dễ thấy chi phí không gian của cách cài đặt trên là O(m), chi phí thời gian là O(nm), với m là tổng của n số. Hãy tự kiểm tra xem tại sao vòng for thứ 2 lại là for downto chứ không phải là for to.

    b) Chia kẹo

    Cho n gói kẹo, gói thứ i có ai viên. Hãy chia các gói thành 2 phần sao cho chênh lệch giữa 2 phần là ít nhất.

    Hướng dẫn: Gọi T là tổng số kẹo của n gói. Chúng ta cần tìm số S lớn nhất thoả mãn:

    • S≤T/2.
    • Có một dãy con của dãy a có tổng bằng S.

    Khi đó sẽ có cách chia với chênh lệch 2 phần là T–2S là nhỏ nhất và dãy con có tổng bằng S ở trên gồm các phần tử là các gói kẹo thuộc phần thứ nhất. Phần thứ hai là các gói kẹo còn lại.

    c) Market (Olympic Balkan 2000)

    Người đánh cá Clement bắt được n con cá, khối lượng mỗi con là ai, đem bán ngoài chợ. Ở chợ cá, người ta không mua cá theo từng con mà mua theo một lượng nào đó. Chẳng hạn 3kg, 5kg…

    Ví dụ: có 3 con cá, khối lượng lần lượt là: 3, 2, 4. Mua lượng 6 kg sẽ phải lấy con cá thứ 2 và và thứ 3. Mua lượng 3 kg thì lấy con thứ nhất. Không thể mua lượng 8 kg.

    Nếu bạn là người đầu tiên mua cá, có bao nhiêu lượng bạn có thể chọn?

    Hướng dẫn: Thực chất bài toán là tìm các số S mà có một dãy con của dãy a có tổng bằng S. Ta có thể dùng phương pháp đánh dấu của bài chia kẹo ở trên rồi đếm các giá trị t mà L[t]=1.

    d) Điền dấu

    Cho n số tự nhiên a1,a2,. ..,an. Ban đầu các số được đặt liên tiếp theo đúng thứ tự cách nhau bởi dấu “?”: a1?a2?…?an. Cho trước số nguyên S, có cách nào thay các dấu “?” bằng dấu + hay dấu – để được một biểu thức số học cho giá trị là S không?

    Hướng dẫn: Đặt L(i,t)=1 nếu có thể điền dấu vào i số đầu tiên và cho kết quả bằng t. Ta có công thức sau để tính L:

    • L(1,a[1]) =1.
    • L(i,t)=1 nếu L(i–1,t+a[i])=1 hoặc L(i–1,t–a[i])=1.

    Nếu L(n,S)=1 thì câu trả lời của bài toán là có. Khi cài đặt, có thể dùng một mảng 2 chiều (lưu toàn bộ bảng phương án) hoặc 2 mảng một chiều (để lưu dòng i và dòng i–1). Chú ý là chỉ số theo t của các mảng phải có cả phần âm (tức là từ –T đến T, với T là tổng của n số), vì trong bài này chúng ta dùng cả dấu – nên có thể tạo ra các tổng âm.

    Bài này có một biến thể là đặt dấu sao cho kết quả là một số chia hết cho k. Ta có thuật giải tương tự bài toán trên bằng cách thay các phép cộng, trừ bằng các phép cộng và trừ theo môđun k và dùng mảng đánh dấu với các giá trị từ 0 đến k–1 (là các số dư có thể có khi chia
    cho k). Đáp số của bài toán là L(n,0).

    e) Expression (ACM 10690)

    Cho n số nguyên. Hãy chia chúng thành 2 nhóm sao cho tích của tổng 2 nhóm là lớn nhất.

    Hướng dẫn: Gọi T là tổng n số nguyên đó. Giả sử ta chia dãy thành 2 nhóm, gọi S là tổng của một nhóm, tổng nhóm còn lại là T–S và tích của tổng 2 nhóm là S*(T–S). Bằng phương pháp đánh dấu ta xác định được mọi số S là tổng của một nhóm (như bài Market) và tìm số S sao
    cho S*(T–S) đạt max.

    III. Biến đổi xâu

    1. Mô hình

    Cho 2 xâu X,F. Xâu nguồn có n kí tự X1X2…Xn , xâu đích có m kí tự F1F2…Fm. Có 3 phép biến đổi:

    • Chèn một kí tự vào sau kí tự thứ i: I i C
    • Thay thế kí tự ở vị trí thứ i bằng kí tự C: R i C.
    • Xoá kí tự ở vị trí thứ i. D i

    Hãy tìm số ít nhất các phép biến đổi để biến xâu X thành xâu F.

    Hướng dẫn:

    Hàm mục tiêu: f: số phép biến đổi.

    Dễ thấy số phép biến đổi phụ thuộc vào vị trí i đang xét của xâu X và vị trí j đang xét cuả xâu F. Do vậy để cài đặt cho bang phương án ta sẽ dùng mảng 2 chiều Gọi L(i,j) là số phép biến đổi ít nhất để biến xâu X(i) gồm i kí tự phần đầu của X (X(i)=X[1..i]) thành xâu F(j) gồm j kí tự phần đầu của F(F(j) =F[1..j]). Dễ thấy F(0,j)=j và F(i,0)=i.

    Có 2 trường hợp xảy ra:

    Nếu X[i]=F[j]:

    X1X2Xi-1 Xi
    F1F2Fj-1 Xi
    thì ta chỉ phải biến đổi xâu X(i-1) thành xâu Y(j-1). Do đó F(i,j)=F(i-1,j-1).

    Ngược lại, ta có 3 cách biến đổi:

    Xoá kí tự X[i]: X1X2Xi-1 Xi
    F1F2Fj-1 Fj
    Xâu X(i-1) thành F(j). Khi đó F(i,j)=F(i-1,j)+1.(Cộng 1 là do ta đã dùng 1 phép xóa)
    Thay thế X[i] bởi F[j]: X1X2Xi-1 Fj

    F1F2Fj-1 Fj
    Xâu X(i-1) thành F(j-1). Khi đó F(i,j)=F(i-1,j-1)+1.
    Chèn F[j] vào X(i): X1X2Xi-1XiFj

    F1F2Fj-1 Fj
    Xâu X(i) thành Y(j-1). Khi đó F(i,j)=F(i,j-1)+1.
    Tổng kết lại, ta có công thức QHĐ:

    • F(0,j)=j
    • F(i,0)=i
    • F(i,j) =F(i-1,j-1) nếu X[i] = Y[j].
    • F(i,j) = min(F(i-1,j),F(i,j-1),F(i-1,j-1))+1 nếu X[i]≠Y[j].

    Bài này ta có thể tiết kiệm biến hơn bằng cách dùng 2 mảng 1 chiều tính lẫn nhau và một mảng đánh dấu 2 chiều để truy vết.

    4. Một số bài toán khác

    a) Xâu con chung dài nhất

    Cho 2 xâu X,Y. Hãy tìm xâu con của X và của Y có độ dài lớn nhất.

    Công thức QHĐ
    Gọi L(i,j) là độ dài xâu con chung dài nhất của xâu X(i) gồm i kí tự phần đầu của X (X(i)=
    X[1..i]) và xâu Y(j) gồm j kí tự phần đầu của Y (Y(j) =Y[1..j]).
    Ta có công thức quy hoạch động như sau:
    • L(0,j)=L(i,0)=0.
    • L(i,j) = L(i-1,j-1)+1 nếu X[i] = Y[j].
    • L(i,j) = max(L(i-1,j), L(i,j-1)) nếu X[i]≠Y[j].
    Cài đặt
    Bảng phương án là một mảng 2 chiều L[0..m,0..n] để lưu các giá trị của hàm QHĐ L(i,j).
    Đoạn chương trình cài đặt công thức QHĐ trên như sau:
    for i:=0 to m do L[i,0]:=0;
    for j:=0 to n do L[0,j]:=0;
    for i:=1 to m do
    for j:=1 to n do
    if X[i]=Y[j] then
    L[i,j]:=L[i–1,j–1]+1
    else
    L[i,j]:=max(L[i–1,j],L[i,j–1]]);
    Như vậy chi phí không gian của bài toán là O(n2), chi phí thời gian là O(n2). Có một phương
    pháp cài đặt tốt hơn, chỉ với chi phí không gian O(n) dựa trên nhận xét sau:
    để tính ô L[i,j]
    của bảng phương án, ta chỉ cần 3 ô L[i–1,j–1],L[i–1,j] và L[i,j–1]. Tức là để tính dòng L[i]
    thì chỉ cần dòng L[i–1]
    . Do đó ta chỉ cần 2 mảng 1 chiều để lưu dòng vừa tính (P) và dòng
    đang tính (L) mà thôi. Cách cài đặt mới như sau:
    for j:=0 to n do P[j]:=0;
    for i:=1 to m do begin
    L[0]: = 0;
    for j:=1 to n do
    if X[i]=Y[j] then
    L[i,j]:=P[j–1]+1
    else L[i,j]:=max(P[j], L[j–1]);
    P: = L;
    end;

    c) Bắc cầu

    Hai nước Anpha và Beta nằm ở hai bên bờ sông Omega, Anpha nằm ở bờ bắc và có M thành phố được đánh số từ 1 đến m, Beta nằm ở bờ nam và có N thành phố được đánh số từ 1 đến n (theo vị trí từ đông sang tây). Mỗi thành phố của nước này thường có quan hệ kết nghĩa với một số thành phố của nước kia. Để tăng cường tình hữu nghị, hai nước muốn xây các cây cầu bắc qua sông, mỗi cây cầu sẽ là nhịp cầu nối 2 thành phố kết nghĩa. Với yêu cầu là các cây cầu không được cắt nhau và mỗi thành phố chỉ là đầu cầu cho nhiều nhất là một cây cầu, hãy chỉ ra cách bắc cầu được nhiều cầu nhất.

    Hướng dẫn: Gọi các thành phố của Anpha lần lượt là a1,a2,…am; các thành phố của Beta là
    b
    1,b2,…bn. Nếu thành phố ai và bj kết nghĩa với nhau thì coi ai bằng” bj. Để các cây cầu
    không cắt nhau, nếu ta đã chọn cặp thành phố (a
    i,bj) để xây cầu thì cặp tiếp theo phải là cặp
    (a
    u,bv) sao cho u>i và v>j. Như vậy các cặp thành phố được chọn xây cầu có thể coi là một
    dãy con chung của hai dãy a và b
    .

    Bài toán của chúng ta trở thành bài toán tìm dãy con chung dài nhất, ở đây hai phần tử “bằng” nhau nếu chúng có quan hệ kết nghĩa.

    d) Palindrom (IOI 2000)

    Một xâu gọi là xâu đối xứng (palindrom) nếu xâu đó đọc từ trái sang phải hay từ phải sang
    trái đều như nhau. Cho một xâu S, hãy tìm số kí tự ít nhất cần thêm vào S để S trở thành xâu
    đối xứng.
    Hướng dẫn: Bài toán này có một công thức QHĐ như sau:
    Gọi L(i,j) là số kí tự ít nhất cần thêm vào xâu con S[i..j] của S để xâu đó trở thành đối xứng.
    Đáp số của bài toán sẽ là L(1,n) với n là số kí tự của S. Ta có công thức sau để tính L(i,j):
    • L(i,i)=0.
    • L(i,j)=L(i+1,j–1) nếu S[i]=S[j]
    • L(i,j)=max(L(i+1,j), L(i,j–1)) nếu S[i]≠S[j]
    Bạn đọc dễ dàng có thể kiểm chứng công thức đó. Ta có thể cài đặt trực tiếp công thức đó
    bằng phương pháp đệ quy có nhớ. Tuy nhiên khi đó chi phí không gian là O(n
    2). Có một
    phương pháp cài đặt tiết kiệm hơn (bạn đọc có thể tham khảo ở bài báo trên của thầy Trần Đỗ
    Hùng), tuy nhiên phương pháp đó khá phức tạp.
    Ta có thuật toán đơn giản hơn như sau:
    Gọi P là
    xâu đảo của S và T là xâu con chung dài nhất của S và P. Khi đó các kí tự của S
    không thuộc T cũng là các kí tự cần thêm vào để S trở thành đối xứng. Đáp số của bài toán sẽ
    là n–k, với k là độ dài của T.
    Ví dụ: S=
    edbabcd, xâu đảo của S là P=dcbabde. Xâu con chung dài nhất của S và P là
    T=
    dbabd. Như vậy cần thêm 2 kí tự là e c vào để S trở thành xâu đối xứng.

    IV. Vali (A)

    1. Mô hình

    Cho n vật, vật i nặng ai và có giá trị bi. Hãy chọn ra một số vật để cho vào balô sao cho tổng
    khối lượng không vượt quá W và tổng giá trị là lớn nhất. Chú ý rằng mỗi vật có thể được chọn
    nhiều lần.

    2. Công thức

    Gọi L(i,j) là tổng giá trị lớn nhất khi được chọn i vật từ 1 đến i cho vào balô với tổng khối
    lượng không vượt quá j
    . L(n,W) sẽ là đáp số của bài toán (là giá trị lớn nhất có được nếu chọn
    n vật và tổng khối lượng không vượt quá W).
    Công thức tính L(i,t) như sau:
    • L(i,0)=0; L(0,j)=0.
    • L(i,j)=L(i,j) nếu t<a
    i.
    • L(i,t)=max(L(i-1,j), L(i,j–a
    i)+bi) nếu t ≥ai.
    Trong đó: L(i–1,j) là giá trị có được nếu không đưa vật i vào balô, L(i,j–a
    i)+bi là giá trị có
    được nếu chọn vật i.

    3. Cài đặt

    Ta có thể dùng một mảng 2 chiều để lưu bảng phương án, tuy nhiên dựa trên nhận xét rằng để
    tính dòng i của bảng phương án chỉ cần dòng i–1, ta chỉ cần dùng 2 mảng một chiều P và L có
    chỉ số từ 0 đến m để lưu 2 dòng đó. Đoạn chương trình con tính bảng phương án như sau.
    L[t]: = 0; {với mọi t}
    for i: = 1 to n do begin
    P:=L;
    for t: = 0 to m do
    if t<a[i] then L[t]:=P[t]
    else L[t]: = max(P[t],P[t–a[i]]);
    end;
    Nếu để ý kĩ bạn sẽ thấy rằng đoạn trình trên chỉ viết giống công thức QHĐ chứ chưa tối ưu.
    Chẳng hạn đã có lệnh gán P:=L, sau đó lại có gán L[t]:=P[t] với các giá trị t<a[i] là không cần
    thiết. Bạn đọc có thể tự cải tiến để chương trình tối ưu hơn.
    Chi phí không gian của cách cài đặt trên là O(m) và chi phí thời gian là O(n.m).

    4. Một số bài toán khác

    a) Farmer (IOI 2004)

    Một người có N mảnh đất và M dải đất. Các mảnh đất có thể coi là một tứ giác và các dải đất
    thì coi như một đường thẳng. Dọc theo các dải đất ông ta trồng các cây bách, dải đất thứ i có
    a
    i cây bách. Ông ta cũng trồng các cây bách trên viền của các mảnh đất, mảnh đất thứ j có bj
    cây bách. Cả ở trên các mảnh đất và dải đất, xen giữa 2 cây bách ông ta trồng một cây ôliu.
    Ông ta cho con trai được chọn các mảnh đất và dải đất tuỳ ý với điều kiện tổng số cây bách
    không vượt quá Q. Người con trai phải chọn thế nào để có nhiều cây ôliu (loài cây mà anh ta
    thích) nhất.
    Hướng dẫn: Dễ thấy mảnh đất thứ i có ai cây ôliu và dải đất thứ j có bj–1 cây ôliu. Coi các
    mảnh đất và dải đất là các “đồ vật”, đồ vật thứ k có khối lượng w
    k và giá trị vk (nếu k là mảnh
    đất i thì w
    k=vk=ai, nếu k là dải đất j thì wk=bj, vk=bj–1). Ta cần chọn các “đồ vật”, sao cho
    tổng “khối lượng” của chúng không vượt Q và tổng “giá trị” là lớn nhất. Đây chính là bài toán
    xếp balô đã trình bày ở trên.

    b) Đổi tiền

    Ở đất nước Omega người ta chỉ tiêu tiền xu. Có N loại tiền xu, loại thứ i có mệnh giá là ai
    đồng. Một người khách du lịch đến Omega du lịch với số tiền M đồng. Ông ta muốn đổi số
    tiền đó ra tiền xu Omega để tiện tiêu dùng. Ông ta cũng muốn số đồng tiền đổi được là ít nhất
    (cho túi tiền đỡ nặng khi đi đây đi đó). Bạn hãy giúp ông ta tìm cách đổi tiền.
    Hướng dẫn: Bài toán này khá giống bài toán xếp balô (“khối lượng” là mệnh giá, “giá trị”
    1), chỉ có một số thay đổi nhỏ:
    số đồng xu mỗi loại được chọn tuỳ ý (trong bài toán xếp balô
    mỗi đồ vật chỉ được chọn 1 lần) và
    tổng giá trị yêu cầu là nhỏ nhất.
    Do đó ta cũng xây dựng hàm QHĐ một cách tương tự: Gọi L(i,t) là số đồng xu ít nhất nếu đổi
    t đồng ra i loại tiền xu (từ 1 đến i). Công thức tính L(i,t) như sau:
    • L(i,0)=0;
    • L(0,t)= ∞ với t>0.
    • L(i,t)=L(i–1,t) nếu t<a
    i.
    • L(i,t)=min(L(i–1,t), L(i,t–a
    i)+1) nếu t ≥ai.
    Công thức này khác công thức của bài xếp balô ở chỗ: dùng hàm min chứ không phải hàm
    max (vì cần tìm cách chọn ít hơn) và nếu chọn đồng xu thứ i thì L(i,t)=L(i,t–ai)+1 (vì ta vẫn
    còn được chọn đồng xu thứ i đó nữa), khác với khi xếp balô là: nếu chọn đồ vật thứ i thì
    L(
    i,t)=L(i–1,t–ai)+bi vì đồ vật i chỉ được chọn một lần.

    V. Nhân ma trận

    1. Mô hình

    Nhân một ma trận kích thước m×n với một ma trận n×p, số phép nhân phải thực hiện là m.n.p. Mặt khác phép nhân các ma trận có tính kết hợp, tức là: (A.B).C = A.(B.C)

    Do đó khi tính tích nhiều ma trận, ta có thể thực hiện theo các trình tự khác nhau, mỗi trình tự tính sẽ quyết định số phép nhân cần thực hiện.

    Cho N ma trận A1,A2…An, ma trận Ai có kích thước là di–1×di. Hãy xác định trình tự nhân ma trận A1.A2…An sao cho số phép nhân cần thực hiện là ít nhất.

    2. Công thức

    Gọi F(i,j) là số phép nhân để tính tích các ma trận từ Aiđến Aj (Ai.Ai+1….Aj).
    • F(i,i)=0.
    • F(i,i+1)=d
    i–1.di.di+1
    • F(i,j) = min(F(i,k)+F(k+1,j)+di–1.dk.dj với k=i+1,i+2,…j–1)
    Công thức hơi phức tạp nên tôi xin giải thích như sau:
    • F(i,i)=0 là hiển nhiên.
    • F(i,i+1) là số phép nhân khi nhân A
    i và Ai+1. Ai có kích thước di–1×di, Ai+1 có kích thước
    d
    i×di+1, do đó F(i,i+1)=di–1.di.di+1.
    • Với j>i+1 thì ta thấy có thể tính Ai.Ai+1….Aj bằng cách chọn một vị trí k nào đó để đặt
    ngoặc theo trình tự:
    A
    i.Ai+1….Aj = (Ai..Ak).(Ak+1..Aj)
    Ma trận kết quả của phép nhân (A
    i..Ak) có kích thước di–1×dk, ma trận kết quả của phép nhân
    (A
    k+1..Aj) có kích thước ddj. Với cách đặt đó ta sẽ mất F(i,k) phép nhân để có kết quả trong
    dấu ngoặc thứ nhất, mất thêm F(k+1,j) phép nhân để có kết quả trong dấu ngoặc thứ hai, và
    cuối cùng mất d
    i–1.dk.dj để nhân 2 ma trận kết quả đó. Từ đó tổng số phép nhân của cách đặt
    đó là: F(i,k)+F(k+1,j)+d
    i–1.dk.dj.
    Ta chọn vị trí k cho số phép nhân ít nhất.

    3. Cài đặt

    Bảng phương án là một mảng 2 chiều F để lưu F(i,j). Chú ý khi cài đặt là để tính được F(i,j),
    ta phải tính F(i,k) và F(k+1,j) trước. Phương pháp đơn giản để làm điều đó là phương pháp đệ
    quy có nhớ.
    Tuy nhiên dựa vào nhận xét là trong công thức QHĐ: j–i lớn hơn k–i và j–k, ta có thể tính
    theo trình tự khác: tính các phần tử F(i,j) với j–i từ nhỏ đến lớn (không phải là tính các giá
    trị F(i,j) với i,j từ nhỏ đến lớn như vẫn làm). Với cách đó, khi tính đến F(i,j) thì ta đã có F(i,k)
    và F(k+1,j).
    Đoạn chương trình tính bảng phương án như sau:
    for i:=1 to n do F[i,i]:=0;
    for i:=1 to n–1 do
    F[i,i+1]: = d[i–1]*d[i]*d[i+1];
    for m:=2 to n–1 do begin
    for i:=1 to n–m do begin
    j:=i+m; F[i,j]:=oo;
    for k:=i+1 to j–1 do
    F[i,j]:=min(F[i,j],
    F[i,k]+F[k+1,j]+d[i–1]*d[k]*d[j]);
    end;
    end;
    Với cách cài đặt trên,chi phí không gian là O(n2), chi phí thời gian là O(n3) (đây là bài toán có
    chi phí lớn nhất trong tất cả các bài toán QHĐ thường gặp).

    4. Một số bài toán khác

    a) Chia đa giác

    Cho một đa giác lồi N đỉnh. Bằng các đường chéo không cắt nhau, ta có thể chia đa giác thành
    N–2 tam giác. Hãy xác định cách chia có tổng các đường chéo ngắn nhất.
    Hướng dẫn: Để đơn giản ta coi mọi đoạn thẳng nối 2 đỉnh đều là “đường chéo” (nếu nối 2
    đỉnh trùng nhau hoặc 2 đỉnh liên tiếp thì có độ dài bằng 0).
    Gọi F(i,j) là tổng độ dài các đường chéo khi chia đa giác gồm các đỉnh từ i đến j thành các
    tam giác. Nếu j<i+3 thì đa giác đó có ít hơn 4 đỉnh, không cần phải chia nên F(i,j)=0. Ngược
    lại ta xét cách chia đa giác đó bằng cách chọn một đỉnh k nằm giữa i,j và nối i,j với k. Khi đó
    F(i,j)=F(i,k)+F(k,j)+d(i,k)+d(k,j);
    d(i,k) là độ dài đường chéo (i,k).
    Tóm lại công thức QHĐ như sau:
    • F(i,j)=0 với j<i+3.
    • F(i,j)=min(F(i,k)+F(k,j)+d(i,k)+d(k,j) với k=i+1,…j–1).
    F(1,n) là tổng đường chéo của cách chia tối ưu.
    b) Biểu thức số học (IOI 1999)
    Cho biểu thức a1•a2•…•an, trong đó ai là các số thực không âm và • là một phép toán + hoặc
    × cho trước. Hãy đặt các dấu ngoặc để biểu thức thu được có kết quả lớn nhất.
    Hướng dẫn: Gọi F(i,j) là giá trị lớn nhất có thể có của biểu thức ai•ai+1•…•aj. Dễ thấy nếu i=j
    thì F(i,j)=a
    i, nếu j=i+1 thì F(i,j)=ai•aj. Nếu j>i+1 thì có thể tính biểu thức ai•ai+1•…•aj bằng
    cách chia thành 2 nhóm: (a
    i•ai+1•…•ak)•(ak+1•…•aj), Khi đó F(i,j)=F(i,k)•F(k+1,j).
    Tóm lại, công thức QHĐ là:
    Trang11

    • F(i,i)=ai
    • F(i,i+1)=ai•ai+1
    • F(i,j)=max(F(i,k)•F(k+1,j) với k=i+1,i+2,..j–1).
    (Chú là là các hạng tử của dãy đều không âm và các phép toán là + hoặc × nên F(i,k) và
    F(k+1,j) đạt max thì F(i,k)•F(k+1,j) cũng đạt max).

    VI. Ghép cặp

    1.Mô hình

    Có n lọ hoa sắp thẳng hàng và k bó hoa được đánh số thứ tự từ nhỏ đến lớn. Cần cằm k bó hoa trên
    vào n lọ sao cho hoa có số thứ tự nhỏ phải đứng trước hoa có số thứ tự lớn. Giá trị thẩm mỹ tương ứng
    khi cắm hoa i vào lọ thứ j là v(i,j) Hãy tìm 1 cách cắm sao cho tổng giá trị thẫm mỹ là lớn nhất. Chú ý
    rằng mỗi bó hoa chỉ được cắm vào 1 lọ và mỗi lọ cũng chỉ cắm được 1 bó hoa. (IOI –1999)

    2. Công thức

    Nhận xét rằng bài toán nêu trên là một bài toán ghép cặp có yêu cầu về thứ tự nên ta có thể
    giải quyết bằng phương pháp QHĐ.
    Hàm mục tiêu: f: tổng giá trị thẩm mỹ của cách cắm.
    Giá trị thẩm mỹ phụ thuộc vào các hoa và các lọ đang được xét nên ta sẽ dùng mảng 2 chiều
    để lưu bảng phương án.
    L(i,j): tổng giá trị thẩm mỹ lớn nhất khi xét đến hoa i và lọ j. Khi tính L(i,j) hoa đang xét sẽ là
    hoa i và lọ j.
    Nếu i = j. Chỉ có một cách cắm L(i,i):= v[1,1]+v[2,2]+…v[i,i]
    Nếu i>j. Không có cách cắm hợp lý
    Nếu i<j: Có 2 trường hợp xảy ra:
    Cắm hoa i vào lọ j. Tổng giá trị thẩm mỹ là L(i-1,j-1)+v(i,j). (Bằng tổng giá trị trước khi
    cắm cộng với giá trị thẩm mỹ khi cắm hoa i vào lọ j)
    Không cắm hoa i vào lọ j (có thể cắm vào lọ trước j), giá trị thẫm mỹ của cách cắm là như
    cũ: L(i,j-1)

    3. Cài đặt

    L[i,j]:= -maxint;
    For i:=1 to k do
    For j:=i to n do
    If i = j then L[i,j]:=sum(i)
    else
    if i<j then L[i,j]:=max(L[i-1,j-1]+v[i,j],L[i,j-1]);

    4. Một số bài toán khác

    a) Câu lạc bộ:( Đề thi chọn HSG Tin Hà Nội năm 2000)

    Có n phòng học chuyên đề và k nhóm học được đánh số thứ tự từ nhỏ đến lớn. Cần xếp k nhóm trên vào n phòng học sao cho nhóm có số hiệu nhỏ được xếp vào phòng có số hiệu nhỏ, nhóm có số hiệu lớn phải được xếp vào phòng có số hiệu lớn.Với mỗi phòng có chứ học sinh,
    các ghế thừa phải được chuyển ra hết, nếu thiếu ghế thì lấy vào cho đủ ghế. Biết phòng i có 

    a(i) ghế, nhóm j có b(j) học sinh. Hãy chọn 1 phương án bố trí sao cho tổng số lần chuyển ghế
    ra và vào là ít nhất.
    Hướng dẫn : Khi xếp nhóm i vào phòng j thì số lần chuyển ghế chính là độ chênh lệch giữa
    số ghế trong phòng i và số học sinh trong nhóm. Đặt v[i,j]:=|a(i)-b(j)|
    b) Mua giày (Đề QG bảng B năm 2003)
    Trong hiệu có n đôi giày, đôi giày i có kích thước hi. Có k người cần mua giày, người i cần
    mua đôi giày kích thước s
    i . Khi người i chọn mua đôi giày j thì độ lệch sẽ là |h(i)-s(j)|. Hãy
    tìm cách chọn mua giày cho k người trên sao cho tổng độ lệch là ít nhất. Biết rằng mỗi người
    chỉ mua 1 đôi giày và 1 đôi giày cũng chỉ có một người mua.
    Hướng dẫn : Lập công thức giải như bài Câu lạc bộ. Chú ý chứng minh tính đúng đắn của bổ
    đề heuristic sau: Cho 2 dãy tăng dần các số dương a
    1a2…an , b1b2…bn. Gọi c1c2…cn là một
    hoán vị của dãy {b
    n}. Khi đó: |a(1)-b(1)|+ |a(2)-b(2)|+…+ |a(n)-b(n)|< |a(1)-c(1)|+ |a(2)-
    c(2)|+…+ |a(n)-c(n)|

    VII. Di chuyển

    1. Mô hình

    Cho bảng A gồm MxN ô. Từ ô (i,j) có thể di chuyển sang 3 ô (i+1,j), (i+1,j–1) và (i+1,j+1). Hãy xác định một lộ trình đi từ hàng 1 đến hàng M sao cho tổng các ô đi qua là lớn nhất.

    2. Công thức

    Gọi F(i,j) là giá trị lớn nhất có được khi di chuyển đến ô (i,j). Có 3 ô có thể đi đến ô (i,j) là (i–1,j), (i–1,j–1) và (i–1,j+1). Do đó ta có công thức QHĐ như sau:

    • F(1,j)=A[1,j]
    • F(i,j)=max(F(i–1,j),F(i–1,j–1),F(i–1,j+1))+A[i,j] với i>1

    3. Cài đặt

    Bảng phương án là bảng 2 chiều F[0..m,0..n]. (Tất cả các ô trên biên đều cho giá trị bằng 0).

    Quá trình tính như sau:

    for i:=1 to m do
    for j: = 1 to n do
    F[i,j]=max[F[i–1,j],F[i–1,j–1],F[i–1,j+1]]+A[i,j];

    Cách cài đặt này cho chi phí không gian và thời gian đều là O(n2). Ta có thể tiết kiệm không gian nhớ bằng cách tính trực tiếp trên mảng A.

    4. Một số bài toán khác

    a) Tam giác (IOI 1994)

    Cho một tam giác gồm các số nguyên không âm. Hãy tính tổng lớn nhất các số trên đường đi từ đỉnh tam giác xuống một điểm nào đó ở đáy tam giác nào đó. Tại mỗi ô ta chỉ có đi thẳng xuống, sang ô bên trái hoặc bên phải.

    Hướng dẫn: Mô tả các phần tử của tam giác số như một ma trận, A[i,j] là phần tử thứ j trên dòng i (với 1≤i≤N và 1≤j≤i). Có 2 ô có thể di chưyển đến ô (i,j) là ô (i–1,j–1) và ô (i–1,j). Gọi F(i,j) là tổng lớn nhất có thể có khi đi đến ô (i,j) ta có:

    • F(1,1)=A[1,1]
    • F(i,1)=F(i–1,1)+A[i,1]
    • F(i,j)=max(F(i–1,j–1),F(i–1,j))+A[i,j]

    b) Con kiến

    Có một ống hình trụ, khi trải phẳng ra có thể là một bảng MxN ô. Giá trị A[i,j] là lượng thức ăn có ở ô ở dòng i cột j. Một con kiến xuất phát từ một ô ở mép bên trái của hình trụ và bò sang mép bên phải. Từ ô (i,j) kiến có thể bò sang 1 trong 3 ô (i–1,j+1), (i,j+1) hoặc (i+1,j+1). (Chú ý: vì ống hình trụ nên kiến đang ở dòng 1 có thể bò xuống dòng M và ngược lại). Bò qua ô nào thì kiến mang theo toàn bộ lượng thức ăn ở ô đó. Hãy tìm đường đi mà kiến kiếm được nhiều thức ăn nhất.

    Hướng dẫn: Để xử lí tình huống hình trụ, ta lưu dòng 0 là dòng M và dòng M+1 là dòng 1. Khi đó tương tự như bài toán ban đầu, gọi F(i,j) là lượng thức ăn kiến có được khi bò đến ô (i,j), ta thiết lập được công thức QHĐ sau:

    • F(i,1)=A[i,1]
    • F(i,j)=max(F(i–1,j–1),F(i,j–1),F(i+1,j+1))+A[i,j] với j>1
  • Bài toán Tháp Hà Nội (Tower of Hanoi)

    Bài toán Tháp Hà Nội (Tower of Hanoi)

    Bài toán Tháp Hà Nội (Tower of Hanoi)

    Bài toán Tháp Hà Nội là một bài toán rất nổi tiếng và kinh điển, rất thích hợp để minh họa cho thuật toán đệ quy.

    Bài toán Tháp Hà Nội là gì?

    Có 3 chiếc cọc được đánh dấu lần lượt là A, B, C và n chiếc đĩa. Các đĩa này có kích thước (đường kính) khác nhau và mỗi đĩa đều có một lỗ ở giữa để lồng vào cọc. Ban đầu, các đĩa đều nằm ở cọc A, trong đó, đĩa có đường kính nhỏ hơn luôn ở nằm trên đĩa đường kính lớn hơn.

    bài toán tháp hà nội

    Yêu cầu : Chuyển n đĩa từ cọc A sang cọc C với các điều kiện sau:

    • Mỗi lần chỉ chuyển được 1 đĩa
    • Trong quá trình chuyển, đĩa nhỏ phải luôn nằm trên đĩa lớn hơn.
    • Cho phép sử dụng cọc B làm cọc trung gian

    Cách giải Bài toán Tháp Hà Nội

    Chúng ta sẽ xét các trường hợp của n:

    • Trường hợp đơn giản nhất, n=1, ta chỉ cần chuyển 1 đĩa từ cọc A sang cọc C.
    • Với n=2, ta chuyển đĩa nhỏ nhất sang cọc B, chuyển đĩa còn lại sang cọc C, và cuối cùng chuyển đĩa nhỏ ở cọc B sang cọc C.
    • Với n>2, giả sử ta đã có cách chuyển n-1 đĩa từ một cọc sang một cọc khác. Như vậy, để chuyển n đĩa từ cọc nguồn sang cọc đích, ta cần chuyển n-1 đĩa từ cọc nguồn sang cọc trung gian. Sau đó chuyển đĩa lớn nhất từ cọc nguồn sang cọc đích. Cuối cùng, chuyển n-1 đĩa từ cọc trung gian sang cọc đích.

    Ví dụ, với n=3, chúng ta phải chuyển 7 lần tất cả như hình sau.

    cách giải bài toán tháp hà nội

    Mã nguồn chương trình bằng Python:

    def TowerOfHanoi(n , source, destination, auxiliary):
       if n==1:
          print("Chuyển đĩa 1 từ cọc",source,"sang cọc",destination)
          return
       TowerOfHanoi(n-1, source, auxiliary, destination)
       print("Chuyển đĩa",n,"từ cọc",source,"sang cọc",destination)
       TowerOfHanoi(n-1, auxiliary, destination, source)
    
    # Ví dụ với n = 4		
    n = 4
    TowerOfHanoi(n,'A','C','B')

    Kết quả chạy chương trình:

    Chuyển đĩa 1 từ cọc A sang cọc B
    Chuyển đĩa 2 từ cọc A sang cọc C
    Chuyển đĩa 1 từ cọc B sang cọc C
    Chuyển đĩa 3 từ cọc A sang cọc B
    Chuyển đĩa 1 từ cọc C sang cọc A
    Chuyển đĩa 2 từ cọc C sang cọc B
    Chuyển đĩa 1 từ cọc A sang cọc B
    Chuyển đĩa 4 từ cọc A sang cọc C
    Chuyển đĩa 1 từ cọc B sang cọc C
    Chuyển đĩa 2 từ cọc B sang cọc A
    Chuyển đĩa 1 từ cọc C sang cọc A
    Chuyển đĩa 3 từ cọc B sang cọc C
    Chuyển đĩa 1 từ cọc A sang cọc B
    Chuyển đĩa 2 từ cọc A sang cọc C
    Chuyển đĩa 1 từ cọc B sang cọc C
  • Giải thuật Đệ quy là gì?

    Giải thuật Đệ quy là gì?

    Giải thuật Đệ quy là gì?

    Đệ quy (recursion) xảy ra khi một sự vật được định nghĩa theo chính nó hoặc thuộc loại của nó. Đệ quy được sử dụng trong nhiều lĩnh vực khác nhau, từ ngôn ngữ học đến logic.

    Ví dụ dễ hiểu nhất của đệ quy là một người đứng bên cạnh một TV đang ghi hình trực tiếp chính người đó như trong hình ảnh dưới đây. Lúc đó, trong TV lại có hình ảnh người đó bên cạnh chiếc TV…

    Giải thuật Đệ quy là gì? 8

    Hoặc trên bìa sách Toán 3 có hình ảnh các em học sinh đang cầm cuốn sách Toán lớp 3.

    chương trình đệ quy là gì

    Ứng dụng phổ biến nhất của đệ quy là trong toán học và khoa học máy tính, trong đó một hàm được định nghĩa bằng cách sử dụng theo định nghĩa của chính nó. Trong Toán học, đệ qui xuất hiện trong các bài toán sử dụng phương pháp quy nạp toán học, các bài toán dãy số sử dụng công thức truy hồi.

    1. Giải thuật Đệ quy là gì?

    Trong lập trình, một đối tượng (hàm, class…) được gọi là đệ quy nếu nó hoặc một phần của nó được định nghĩa thông qua chính nó.

    Chúng ta thường gặp nhiều nhất là các hàm đệ quy. Chẳng hạn, ta có hàm factorial(n) để tính giai thừa của số tự nhiên n thì hàm này có thể được định nghĩa thông qua lời gọi đến chính nó là factorial(n) = n * factorial(n-1)

    Tuy nhiên, cũng giống như phương pháp quy nạp trong Toán học. Nếu cứ gọi đến chính nó mãi như thế thì chương trình không có điểm dừng, nên chúng ta luôn phải có những trường hợp đặc biệt được tính toán/quy ước sẵn. Chẳng hạn, đối với hàm tính giai thừa, chúng ta phải quy ước factorial(0) = 1 để chương trình gọi đến factorial(0) thì sẽ dừng lại và sử dụng luôn giá trị được cung cấp sẵn này. Mời bạn xem chi tiết chương trình tính giai thừa ở phần sau bài viết này.

    Hàm đệ quy có thể chứa lời gọi trực tiếp đến chính nó hoặc lời gọi đến hàm khác mà hàm này lại chứa lời gọi đến chính nó.

    2. Đặc điểm của hàm đệ quy

    Một hàm đệ quy gồm 2 phần:

    • Phần cơ sở: Điều kiện để thoát khỏi đệ quy. Nếu như không có phần này, hàm đệ quy sẽ thực hiện mãi mãi gây ra tràn bộ nhớ Stack.
    • Phần đệ quy: Thân hàm có chứa phần gọi đệ quy, thực hiện cho đến khi thỏa mãn điều kiện ở phần cơ sở.

    Ưu nhược điểm của chương trình đệ quy

    • Ưu điểm: Chương trình rất ngắn gọn và dễ đọc, dễ hiểu.
    • Nhược điểm: Chương trình chạy chậm và tốn nhiều bộ nhớ.

    Bài toán đệ quy

    Đó là những bài toán mang bản chất đệ quy. Nghĩa là những bài toán này có thể được phân rã thành các bài toán nhỏ hơn, đơn giản hơn nhưng có cùng dạng với bài toán ban đầu. Những bài toán nhỏ lại được phân rã thành các bài toán nhỏ hơn. Cứ như vậy, việc phân rã chỉ dừng lại khi bài toán con đơn giản đến mức có thể suy ra ngay kết quả mà không cần phải phân rã nữa. Ta phải giải tất cả các bài toán con rồi kết hợp các kết quả đó lại để có được lời giải cho bài toán lớn ban đầu. Cách phân rã bài toán như vậy gọi là “chia để trị” (devide and conquer), là một dạng của đệ quy.

    3. Một số ví dụ về đệ quy

    Một số ví dụ kinh điển về đệ quy như hàm tính giai thừa, tính tổng, tìm số hạng của dãy Fibonacci… Dưới đây, chúng ta cùng sử dụng ngôn ngữ Dart để giải quyết các bài toán này.

    Tính giai thừa bằng đệ quy

    Đề bài. Viết chương trình tính giai thừa của một số tự nhiên n.

    Giả mã của hàm tính giai thừa factorial(n) như sau:

    def factorial(n) {
      nếu n = 0 trả về kết quả 1;
      nếu n > 0 trả về kết quả n * factorial(n-1);
    }

    Dưới đây là mã nguồn chương trình viết bằng ngôn ngữ Python

    def factorial(n):     
        if (n==1 or n==0):
            return 1
        else:
            return (n * factorial(n - 1)) 
    
    print(factorial(7))//kết quả 5040

    Mã nguồn viết bằng ngôn ngữ Dart

    int factorial(int n) {
      if (n == 0)
        return 1;
      else
        return n * factorial(n - 1);
    }
    
    void main() {
      print(factorial(6)); //kết quả 720
    }

    Bạn có thể tham khảo thêm các bài tập khác bằng ngôn ngữ Dart 50 bài tập lập trình Dart cơ bản

    Tính tổng bằng đệ quy

    Viết chương trình tính tổng các số tự nhiên từ 1 tới n, sử dụng đệ quy.

    int sum(int n) {
      if (n == 1)
        return 1;
      else
        return n + sum(n - 1);
    }
    
    void main() {
      print(sum(100)); //kết quả 5050
    }

    Tìm số Fibonacci bằng đệ quy

    Viết chương trình tính số fibonacci thứ n.

    int fibo(int n) {
      if (n == 1 || n == 2)
        return 1;
      else
        return fibo(n-1) + fibo(n-2);
    }
    
    void main() {
      print(fibo(20)); //kết quả 6765
    }

    Tính số tổ hợp bằng đệ quy

    Viết chương trình tính số tổ hợp chập k của n phần tử.

    Chúng ta sử dụng 3 kiến thức sau:

    • $C^k_n=C^{k}_{n-1}+C^{k-1}_{n-1}$
    • $C^0_n=C^{n}_{n}=1$
    • $C^1_n=n$

    Mã nguồn chương trình như sau:

    int bin_coefficient(int k, int n) {
      if (k == 0 || k == n) return 1;
      if (k == 1) return n;
      return bin_coefficient(k, n - 1) + bin_coefficient(k - 1, n - 1);
    }
    
    void main() {
      print(bin_coefficient(3, 5)); //kết quả 10
      print(bin_coefficient(7, 10)); //kết quả 120
    }

    Bạn có thể xem thêm Bài toán Tháp Hà Nội được giải bằng đệ quy.

    bài toán tháp hà nội

    Các loại bài toán đệ quy

    Đệ quy có thể được phân chia thành các loại:

    • Đệ quy tuyến tính (Linear Recursion): Mỗi lần thực thi chỉ gọi đệ quy một lần, chẳng hạn hàm tính giai thừa.
    • Đệ quy nhị phân (Binary Recursion): Mỗi lần thực thi có thể gọi đệ quy 2 lần, ví dụ tính số tổ hợp chập k của n, hoặc tìm số Fibonacci ở trên.
    • Đệ quy lồng nhau (Nested Recursion): Tham số trong lời gọi đệ quy là một lời gọi đệ quy, đệ quy lồng chiếm bộ nhớ rất nhanh.
    • Đệ quy tương hỗ (Mutual Recursion): Các hàm gọi đệ quy lẫn nhau.
    • Quay lui (Backtracking). Trong lập trình, có một chiến lược giải bài toán một cách đầy đủ nhất, đảm bảo đủ mọi trường hợp bằng phương pháp Thử và Sai (Try and Error). Bạn có thể xem thêm trong bài toán Thuật toán quay lui và minh họa. Ví dụ điển hình là Bài toán xếp hậu (N-Queens)

    4. Bài tập lập trình sử dụng Đệ quy

    Sử dụng đệ quy quay lui để giải bài tập sau:

    Bài 1. Viết chương trình tính tích các số tự nhiên liên tiếp từ 1 tới n.

    Bài 2. Viết chương trình tính tổng các số tự nhiên lẻ liên tiếp từ 1 tới n.

    Bài 3. Viết chương trình tính tích các số tự nhiên liên tiếp từ 1 tới n.

    Bài 4. Đếm số lượng chữ số của số nguyên dương n.

    Bài 5. Tìm UCLN của 2 số nguyên dương ab.

    Bài 6. Tính lũy thừa n^k với nk là hai số nguyên dương được nhập vào từ bàn phím.