PHẦN BÀI TẬP
Bạn có thể xem hoặc tải về tại: [OneDrive] [Google Drive]PHẦN HƯỚNG DẪN - GỢI Ý GIẢI MẪU
Bài 1: Cấu trúc của một cái tên luôn là: Phần họ [khoảng cách] Phần tên lót [khoảng cách] Phần tênDo vậy, dù phần tên lót có hay không, chúng ta cũng dễ dàng thấy được, phần họ luôn nằm ở vị trí đầu tiên và phần tên luôn nằm ở vị trí cuối cùng. Vì vậy chúng ta dễ dàng lấy được hai phần này bằng hàm StringSplit - tách các ký tự.
Vấn đề cuối cùng chúng ta sẽ lấy phần tên lót như thế nào? Có 2 cách giải mẫu như sau:
Cách 1: dễ thấy rằng, phần tên lót luôn nằm giữa hai phần họ và tên, điều đó đồng nghĩa với việc tên lót luôn nằm giữ vị trí đầu và cuối. Vì vậy chúng ta có thể nối chuỗi từ vị trí [2] tới vị trí [cuối - 1].
Cách 2: khi lấy được phần họ và tên, đồng nghĩa với việc bạn có thể dùng StringLen để lấy các số lượng ký tự bên trong nó. Phần họ luôn nằm bên trái, vì vậy có thể dùng StringTrimRight để cắt bỏ phần họ dựa vào số ký tự lấy được ở phần họ cộng cho 1 (1 này chính là ký tự khoảng trắng), và tương tự StringTrimLeft với phần họ. Chuỗi cuối cùng nhận được chính là phần tên lót.
Bài 2: các ký tự tiếng Việt bao gồm: á,à,ả,ã,ạ,â,ấ,ầ,ẩ,ẫ,ậ,ă,ắ,ằ,ẵ,ặ,ó,ò,ỏ,õ,ọ,ô,ố,ồ,ổ,ỗ,ộ,ơ,ớ,ờ,ở,ỡ,ợ,í,ì,ỉ,ĩ,ị,ý,ỳ,ỹ,ỷ,ỵ,é,è,ẻ,ẽ,ẹ,ê,ế,ề,ể,ễ,ệ,ú,ù,ũ,ủ,ụ,ư,ứ,ừ,ữ,ử,ự,đ.
Ta có thể dùng 1 biến, để lưu các ký tự này lại dưới dạng chuỗi. ví dụ đó là biến $string . Sau đó bạn có thể dùng StringSplit để tách các ký tự đó ra theo dấu ','. Mục đích của việc tách là để chạy 1 hàm for từ 1 đến vị trí cuối là chữ đ và sau đó chúng ta dùng StringReplace để thay thế từ từ.
Trong hàm For đó, để nhận biết được ký tự nào thay thế với ký tự nào, bạn có thể dùng điều kiện If, ở đây tôi ví dụ, các ký tự được thay thế bằng chữ "a" thì $i trong hàm For phải bé hơn hoặc bằng 16. Lý do là vì 16 ký tự đầu trong chuỗi mà tôi tách được đều thay thế bằng chữ "a". Lặp lại điều này tương tự với các ký tự còn lại.
Bài 3: Giả sử, giá trị trả về của InputBox nhập chuỗi nằm trong biến $input, giá trị trả về của InputBox nhập từ cần tìm nằm trong $word. Sau đó tách $input ra bằng hàm StringSplit với ký tự tách là dấu phẩy ",". Cuối cùng bạn cho chạy 1 hàm For từ vị trí 1 đến vị trí cuối tách được, dùng hàm If để so sánh nếu bất kỳ ký tự tại vị trí nào bằng $word thì hiển thị 1 bảng Msgbox báo tìm được ở vị trí đó.
Lưu ý: sau khi tìm được, tuyệt đối không được ExitLoop vòng lặp For. Lý do: vì trong 1 chuỗi có thể có nhiều vị trí, nếu ExitLoop vòng lặp đồng nghĩa với việc bạn chỉ xuất ra mỗi 1 vị trí tìm được.
Bài 4: để biết khi nào hết dòng trong file Inputbox, bạn có thể dùng cách sau:
$i = 1
While 1
$read = FileReadLine($file,$i) ; trong đó biến $file là đường dẫn của file hoặc file handle trả về từ FileOpen
If $read = '' Then ExitLoop ; nếu giá trị đọc mà không có gì cả (rỗng) thì thoát vòng lặp, nghĩa là đọc xong rồi
WEnd
hoặc
#include
$line = _FileCountLines($file) ; trong đó biến $file là đường dẫn của file
; Hàm _FileCountLines trong thư viện File.au3 sẽ trả về tổng số dòng có trong file
For $i = 1 to $line
$read = FileReadLine($file,$i)
Next
Sau đó đến việc tách ra các tên của đường dẫn. Trong ví dụ bên trên, $read chính là giá trị lấy được từ các dòng trong file. Các dòng đó đều có định dạng ".....\tên_file.đuôi_mở_rộng" và cái chúng ta cần lấy chính là tên file.Dễ thấy, nếu bạn tách chuỗi trên theo ký tự "\" thì ta lấy được phần "tên_file.đuôi_mở_rộng" nằm ở ngăn cuối của mảng trả về dễ dàng. Tiếp theo chúng ta chỉnh cần tách chuỗi vừa lấy được theo dấu "." thì chúng ta dễ dàng thu được phần "tên_file" nằm ở vị trí đầu tiên của mảng trả về.
Bài 5: bài rất rất dễ, chỉ khó ở chỗ làm sao lấy được các con số để tính toán. Giả sử, giá trị chúng ta nhận được lưu tại biến $input, và giả sử $input nhận được giá trị cụ thể là "3d11h20m1s"
Cách 1: Dùng StringReplace, replace toàn bộ các ký tự d,h,m,s thành dấu "-". Lúc này chuỗi chúng ta còn lại sẽ là "3-11-20-1-".
Lúc này việc tách lấy số quả là điều đơn giản. Chỉ cần dùng StringSplit, tách với ký tự "-" thì chúng ta thu được ngăn 1 của mảng trả về là ngày, ngăn 2 là giờ, 3 là phút và 4 là giây. Chỉ cần tính toán từ ngày, giờ, phút, giây ra giây nữa là hoàn tất.
Cách 2: StringSplit không những có khả năng tách 1 ký tự điều kiên, mà ta còn có thể cho nó tách nhiều ký tự cùng lúc. Ví dụ 1 chuỗi: 3d11h20m1s bị ngăn cách bởi các ký tự d,h,m,s. Thì chỉ cần tách bằng các ký tự đó như sau:
$time = StringSplit($input,'dhms')
Thì chúng ta dễ dàng có được ngăn thứ 1 của mảng trả về (tức $time[1]) chính là ngày, tương tự với giờ, phút, giây.Bài 6:
a) Dòng 1 chính là các số hạng có trong file. Hay nói cách khác chính là tổng số dòng - 1 ~> số dòng = dòng 1 + 1.
Khởi tạo 1 biến $min và $max, gán hai biến này cho giá trị đọc được của dòng 2 trong file (tức là số hạng thứ nhất) để dùng cho mục đích so sánh.
Chạy 1 hàm For từ dòng 2 đến cuối dòng. Sau đó tiến hành so sánh, nếu $min mà lớn hơn dòng hiện tại thì ta gán min cho dòng hiện tại, tương tự với $max. Và sau khi duyệt hết, cái bạn có chính là min và max của các số hạng có trong file.
b) Đầu tiên, dùng hàm For chạy ngược từ cuối chuỗi đến đầu chuỗi. Mà cứ cách 3 đơn vị chạy thì gán dấu phẩy vào
For $i = StringLen($read)-3 To 1 Step -3 ; chạy từ vị trí thêm dấu phẩy đầu tiên tính từ phải sang, mỗi lần chạy lùi 3 đơn vị
; code
Next
Để thêm dấu phẩy vào, có thể dùng _StringInsert. Hoặc dùng kiến thức đã học là nối chuỗi.Bài 7:
a) Tính tổng bằng cách tách các chuỗi nhận được từ Input. Sau đó đặt một biến $tong với giá trị ban đầu là 0. Chạy một vòng lặp For để cộng tất cả các giá trị tách được lại.
b) Thuật toán sắp xếp (google). Nói nôm na, chúng ta có 1 mảng: $a[1], ..., $a[n]
Thì ta sẽ sắp xếp từ bé tới lớn bằng cách, so sánh lần lượt 2 phần tử kề nhau ($a[$i] và $a[$i+1] với $i chạy từ 1 tới n-1), nếu $a[$i] >$a[$i+1] thì tráo đổi 2 phần tử này.
Cứ 1 lần chạy vòng lặp for như vậy, ta sẽ có được 1 phần tử lớn nhất được đẩy về phía bên phải. ~> một mảng có n số hạng thì cần chạy n vòng lặp for như vậy.
Và để code chạy nhanh hơn, thì sau mỗi lần chạy vòng lặp For, ta giảm điểm kết thúc nó cho 1. Giả sử lúc đầu For chạy đến 5, thì lần 2 For chỉ chạy đến 4, lần 3 For chỉ chạy đến 3,... Lý do là vì ta đã đẩy được số hạng lớn nhất về cuối phía bên phải sau mỗi lần For, thì ta cũng không cần thiết phải chạy For đến nó làm gì sau các lần lặp sau.
BÀI GIẢI MẪU
Xem bài giải mẫu tại đây
BÀI TẬP BUỔI 3
Xem hoặc tải về tại: [OneDrive] [Google Drive]HƯỚNG DẪN LÀM BÀI
- Xem hướng dẫn làm bài 6: tại đây- Xem hướng dẫn làm bài 5: tại đây
Bài 1:
Ta phải hiểu được tư duy bài toán, tam giác vuông có cạnh huyền (c) và hai cạnh góc vuông (a,b). Thì một tam giác vuông phải thỏa: c^2=a^2+b^2 (Pytago).
Mà c > a+b. Vì vậy ta biết được, c là cạnh lớn nhất. Từ đó, ta tìm c trước, còn hai cạnh còn lại là a, b.
Đầu tiên, ta đọc giá trị tại mỗi dòng của Input. Tách các giá trị đó ra, ta được các cạnh:
$tam_giac_vuong = 0 ; biến đếm, đếm xem có bao nhiêu tam giác vuông trong file input.txt
$line = _FileCountLines("input.txt") ; đếm số dòng có trong file input.txt
For $i = 1 to $line
$read = FileReadLine("input.txt",$i) ; đọc giá trị trong mỗi dòng input
$tach = StringSplit($read,',') ; tách giá trị đó ra, ta được 3 cạnh là $tach[1], $tach[2], $tach[3]
$tach[1] = number($tach[1]) ; ép kiểu chuỗi về kiểu số để ta tính toán và so sánh
$tach[2] = number($tach[2])
$tach[3] = number($tach[3])
; các dòng code tiếp theo
Next
Sau đó, ta kiểm tra 3 cạnh đó có phải là tam giác vuông hay không bằng cách tìm cạnh lớn nhất chính là cạnh huyền. Ta dùng hàm _Max (xem chi tiết trong file help)
Local $c = _Max ( $tach[1], $tach[2]) ; tìm cạnh lớn nhất giữa hai cạnh 1 và 2
$c = _Max ($c, $tach[3]) ; tình cạnh lớn nhất giữa cạnh vừa tìm được với cạnh 3
; HOẶC CÓ THỂ DÙNG GỌN NHƯ SAU
Local $c = _Max ( $tach[1], _Max ($tach[2], $tach[3]))
Rồi chỉ việc dùng toán học để so sánh c^2 = a^2+b^2 nữa là xong ^^, ta tìm kết quả của a^2+b^2 bằng cách cộng bình phương các cạnh khác c như sau:
Local $a_b = 0 ; tổng a^2 và b^2
For $j = 1 to 3 ; vì vòng lặp trên chúng ta đã dùng i, vòng lặp nằm trong vòng lặp đó nên chúng ta phải dùng j để tránh đụng chạm giá trị giữa hai biến chạy
If $tach[$j] < $c Then $a_b += $tach[$j]^2 ; nếu cạnh $i mà nhỏ hơn cạnh huyền ~> đó là cạnh góc vuông ~> cộng tổng bình phương nó lại
Next
If $a_b = $c^2 Then $tam_giac_vuong +=1 ; nếu cạnh huyền bình phương = tổng trên ~> đúng Pytago ~> tam giác vuông ~> cộng biến đếm lên cho 1
Việc còn lại sau khi thoát vòng lặp chỉ là hiển thị Msgbox báo xem có bao nhiêu tam giác vuông.Bài 2:
Gọi $n là biến mà nhận giá trị từ Inputbox.
$n = InputBox("Input","Mời bạn nhận số n")
Sau đó, ta sẽ tính: 1+2+3+...+2n bằng cách dùng vòng lặp For đã học:
$tong = 0 ; tạo biến tổng để cộng
For $i = 1 to 2*$n ; chạy từ 1 tới 2n
$tong += $i
Next
Thế là xong. Nhưng ta có thể không dùng vòng lặp vì chính chất sau: 1+2+3+4+...+n = n(n+1)/2 . Vậy thì trong bài toán này, ta áp dụng:$a = 2*$n ; đơn giản hóa phép tính, gọi $a là 2n
$tong = ($a*($a+1))/2 tổng sẽ bằng a(a+1)/2 chính là tổng của 1+2+3+...+2n
Việc tiếp theo chỉ là mở notepad lên và xuất ra giá trị trên notepad
Run("notepad") ; chạy notepad
WinWait("Untitled - Notepad", "") ; đợi Notepad hiển thị
Send($tong) ; send các ký tự của tổng vào
Bài 3:
Ta có thể tư duy bài này đơn giản như sau, tìm ra số lớn nhất, rồi tìm số lớn nhì bằng cách tìm số nào lớn hơn mọi số còn lại mà bé hơn số lớn nhất. Hay đơn giản hơn là số nào bé hơn số lớn nhất thì ta xét nó với số lớn nhì, nếu nó lớn hơn số lớn nhì thì nó chính là số lớn nhì
Việc đầu tiên là ta khởi tạo các biến, và chạy giá trị từ 1 tới vô hạn, đến khi nào giá trị ta đọc bằng rỗng thì đồng nghĩa với việc kết thúc chương trình:
$i = 1 ; khởi tạo biên chạy
While 1 ; vòng lặp vô hạn
$so_hang = IniRead("Input.ini","NUMBER",$i,'') ; đọc giá trị tại section NUMBER, value $i, nghĩa là số hạng thứ $i, trả về rỗng nếu ko tìm được giá trị
If $so_hang = '' then ExitLoop ; nếu đọc rỗng thì thoát vòng lặp
$i += 1 ; tăng i lên cho 1
; tiếp tục code so sánh và tìm số lớn nhất, số lớn nhì
WEnd
Tuy nhiên ta đã được tìm hiểu về InireadSection vì vậy đơn giản hơn sẽ là:
$so_hang = IniReadSection("input.ini","NUMBER") ; đọc các key và value trong section number
$so_lon_nhat = Number($so_hang[1][1]) ; gán giá trị số lớn nhất ban đầu cho số hạng đầu tiên (value đầu tiên)
$so_lon_nhi = Number($so_hang[1][1]) ; gán giá trị số lớn nhì ban đầu cho số hạng đầu tiên (value đầu tiên)
For $i = 1 to $so_hang[0][0]
If number($so_lon_nhat) < Number($so_hang[$i][1]) Then
$so_lon_nhat = Number($so_hang[$i][1])
ElseIf number($so_lon_nhi) < Number($so_hang[$i][1]) Then
$so_lon_nhi = Number($so_hang[$i][1])
EndIf
Next
Cuối cùng là xuất ra Msgbox thông báo về số lớn nhì.Bài 4:
Ta gọi $a, $b, $c là ba biến nhận 3 giá trị Inputbox nhập cạnh của 1 tam giác.
$a = Inputbox("Input","Mời nhập cạnh 1")
$b = Inputbox("Input","Mời nhập cạnh 2")
$c = Inputbox("Input","Mời nhập cạnh 3")
Một tam giác đều là khi ba cạnh của tam giác bằng nhau. Ta so sánh từng cặp cạnh, nếu bằng nhau nghĩa là tam giác đều:If $a = $b And $a = $c Then Msgbox(64,"Thông báo","Đây là tam giác đều")
; HOẶC
If $a = $b And $b = $c Then Msgbox(64,"Thông báo","Đây là tam giác đều")
; HOẶC TƯƠNG TỰ
Khi chứng minh được đó là tam giác đều, ta mở notepad và vẽ. Chúng ta để ý ví dụ của đề bài, số hàng vẽ = độ dài cạnh (3,3,3 thì vẽ 3 hàng; 4,4,4 thì vẽ 4 hàng)Và tương tự, chúng ta để ý số lượng dấu sao của mỗi hàng tăng theo số lẻ 1, 3, 5, 7,.... Để ý cả các khoảng trắng để canh lề ở các hàng giảm dần từ n-1 đến 0 (trong đó n là độ dài cạnh)
Nắm được các quy tắc chung trên, ta dễ dàng vẽ được một tam giác. Gọi hàm For chạy từ 1 tới n (n là độ dài cạnh), mỗi lần chạy ta xét 1 hàng. Đầu tiên chúng ta sẽ send các khoảng cách với dòng 1 là (n-1) khoảng cách cho tới dòng n là (n-n) khoảng cách. Tiếp theo ta Send các dấu sao để vẽ, tới dòng 1 ta vẽ 1 dấu sao, dòng 2 ta vẽ 3 dấu sao, dòng n ta vẽ (n*2-1) dấu sao.
; Mở notepad như bài 2 rồi vẽ
For $i = 1 to $a
; vẽ khoảng cách căn lề, dòng $i thì vẽ ($a - $i) khoảng cách
For $j = 1 to $a-$i
Send(" ")
Next
; vẽ dấu sao, dòng $i thì vẽ ($i*2-1) dấu sao
For $j = 1 to $i*2-1
Send("*")
Next
Send("{Enter}") ; xuống dòng
Next
Vậy là xong chương trình ^^
BÀI GIẢI MẪU
Xem bài giải mẫu tại đây
PHẦN BÀI TẬP
Bạn có thể xem hoặc tải file pdf: [OneDrive] [GoogleDrive]HƯỚNG DẪN - GỢI Ý GIẢI
Bài 1 và 2:Xem lại video buổi 4
Bài 3:
Nội dung bài này chúng ta sẽ lấy lại hàm tìm ước chung lớn nhất giữa hai số hạng ở bài 1. Giả sử hàm đó gọi là _UCLN($a,$b).
Đầu tiên, chúng ta xây dựng hàm cho phép truyền tham số là mảng vào như sau:
Func _UCLN2(ByRef $mang)
EndFunc
Trong đó _UCLN2 sẽ là tên hàm mà chúng ta sử dụng cho bài 3 này, $mang chính là tham trị cho phép truyền tham số là mảng vào.Tiếp theo, ta duyệt toàn bộ các phần tử trong mảng để tìm ra các giá trị sai yêu cầu và return, set error.
Cuối cùng là ta so sánh từng phần tử với một phần tử khác để tìm ra cặp số có UCLN lớn nhất. Ý tưởng như sau:
Giả sử tôi có 5 số hạng là: a, b, c, d, e. Sau đó ta tìm UCLN của a và b, rồi a và c, rồi a và d, a và e. Tiếp theo ta tìm UCLN phần tử thứ hai là b với c, b với d và b với e, cứ tương tự như vậy cho đến phần tử d, UCLN d với e thì ngưng. Nghĩa là ta tìm UCLN phần tử $i với các phần tử đứng sau $i.
For $i = 0 to UBound($mang)-2
For $j = $i+1 To UBound($mang)-1
If _UCNL($mang[$i],$mang[$j]) > $max Then $max = _UCNL($mang[$i],$mang[$j])
Next
Next
Bài 4:Xem bài viết hướng dẫn sau.
i'm opdo
Xin chào, mình là opdo - một đứa mê những dòng code vô tận. Rất cám ơn vì bạn đã ghé thăm blog của mình ^^. Hi vọng được bạn ủng hộ để blog mình phát triển hơn