1. Trang chủ
  2. » Giáo Dục - Đào Tạo

Kỹ năng dùng mảng một chiều để xử lý số nguyên lớn giúp giải các bài toán khó trong lập trình pascal

21 185 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 21
Dung lượng 175 KB

Nội dung

Tuy nhiên khi thực hiện các phéptính với số nguyên ngoài phạm vi biểu diễn được cung cấp có nhiều hơn 20 chữsố ta cần thiết kế cách biểu diễn và các hàm thực hiện các phép toán cơ bản vớ

Trang 1

MỤC LỤC

A MỞ ĐẦU ………

I Lí do chọn đề tài ………

II mục đích nghiên cứu ……… ………

III Đối tượng nghiên cứu ……….………

IV Phương pháp nghiên cứu ………

2 2 2 2 2 B NỘI DUNG I Cơ sở lí luận ……… 3

II Thực trạng vấn đề trước khi áp dụng ……… 3

III Giải pháp sử dụng ……… 3

Phần một: XÂY DỰNG CÁC PHÉP TOÁN SỐ HỌC TRÊN SỐ LỚN … 3

1.1. Biểu diễn số nguyên lớn……… 3

1.2. Xây dựng các phép toán số học ……… 5

1.2.1 Phép so sánh ……… 5

1.2.2 Phép cộng một số lớn với một số nhỏ ……… 5

1.2.3 Cộng hai số nguyên lớn ……… 6

1.2.4 Phép trừ ……… 6

1.2.5 Phép nhân một số lớn với một số nhỏ ……… 7

1.2.6 Phép nhân hai số nguyên lớn ……… 7

1.2.7 Phép chia một số nguyên lớn cho một số nguyên nhỏ (lấy phần thương nguyên (div) và dư (mod)) ………

8 1.2.8 Phép chia hai số nguyên lớn (lấy phần thương nguyên (div) và dư (mod)) ………

8 Phần hai: MỘT SỐ BÀI TOÁN ỨNG DỤNG XỬ LÝ SỐ LỚN ……… 9

2.1 Bài toán 1 Tính giai thừa ……….……… 9

2.2 Bài toán 2 (Đề Bảng C Tin học trẻ không chuyên toàn quốc) ….……… 10

2.3 Bài toán 3 (Đề thi OLIMPIC Tin học sinh viên Việt Nam 2005) ….… 12

2.4 Bài toán 4 (Đề thi OLP 2004) ……… 15

Phần ba: bài tập luyện tập ……… … 18

IV Hiệu quả của sáng kiến ……… 20

C KẾT LUẬN, KIẾN NGHỊ ……… 21

I Kết luận ……… 21

II Kiến nghị ……… 21

Trang 2

A MỞ ĐẦU

I Lí do chọn đề tài.

Trong mỗi ngôn ngữ lập trình thường có một số kiểu dữ liệu chuẩn chobiết phạm vi giá trị có thể lưu trữ, dung lượng bộ nhớ cần thiết để lưu trữ và xácđịnh các phép toán có thể tác động lên dữ liệu Chẳng hạn trong Turbo Pascal,một số kiểu dữ liệu dạng số nguyên bao gồm: byte, integer, word, longint, int64,qword Trong đó kiểu qword có phạm vi lớn nhất, mỗi giá trị lưu trữ trong 8byte cho phép biến lưu số tối đa có 20 chữ số Tuy nhiên khi thực hiện các phéptính với số nguyên ngoài phạm vi biểu diễn được cung cấp (có nhiều hơn 20 chữsố) ta cần thiết kế cách biểu diễn và các hàm thực hiện các phép toán cơ bản vớicác số nguyên lớn

Gần đây trong các kỳ thi học sinh giỏi người ta thường hay đưa ra các bàitoán cần kết hợp cả xử lý số lớn Vì vậy tìm hiểu về biểu diễn số lớn và các phéptoán với số lớn là cần thiết Trong khuôn khổ của đề tài này, tôi đưa ra cách biểudiễn số nguyên không âm lớn và các phép toán trên đó

Cụ thể Tên đề tài: “KỸ NĂNG DÙNG MẢNG MỘT CHIỀU ĐỂ XỬ LÝ SỐ

NGUYÊN LỚN GIÚP GIẢI CÁC BÀI TOÁN KHÓ TRONG LẬP TRÌNH PASCAL”

II Mục đích của đề tài

Sử dụng các ví dụ cụ thể về các số nguyên lớn để học sinh nắm được phương

pháp chuyển đổi Và thông qua các ví dụ đó hướng dẫn học sinh làm một số bàitoán ứng dụng sử lí số nguyên lớn

III Đối tượng nghiên cứu.

Học sinh giỏi khối 11 tại trường THPT NGỌC LẶC

Sử dụng máy tính để chạy các chương trình

IV Phương pháp nghiên cứu

- Kết hợp thực tiễn việc ôn luyện học sinh giỏi ở trường THPT THPT NGỌCLẶC

- Có tham khảo các tài liệu về ngôn ngữ lập trình Pascal và tài liệu về sáng kiếnkinh nghiệm

Trang 3

B NỘI DUNG I.Cơ sở lí luận

Khi giải quyết các bài toán về số trong pascal ta dùng các kiểu dữ liệu sau:byte, integer, word, longint, int64, qword trong đó kiểu qword có phạm vi lớnnhất cho phép biến lưu số tối đa có 20 chữ số Khi số nguyên quá lớn vượt quagiới hạn này (ví dụ số nguyên 21 số trở lên) thì việc lưu trữ nó bằng các kiểu dữliệu trên là điều không thể

II Thực trạng vấn đề trước khi áp dụng

1 Thuận lợi:

Được sự quan tâm của Sở Giáo dục & Đào tạo và Ban giám hiệu nhà trường,

bộ môn Tin học được trang bị phòng máy tính cùng với các máy chiếu phục vụcho nhu cầu công tác giảng dạy ứng dụng CNTT của giáo viên

III.Giải pháp sử dụng

Phần một: XÂY DỰNG CÁC PHÉP TOÁN SỐ HỌC TRÊN SỐ LỚN

1.1 Biểu diễn số nguyên lớn

Thông thường người ta sử dụng các cách biểu diễn số nguyên lớn sau:

Xâu kí tự: Mỗi kí tự của xâu tương ứng với một chữ số của số nguyên lớn tính từ

trái qua phải

Mảng các số: Sử dụng mảng lưu các chữ số (hoặc một nhóm chữ số) của số

Trang 4

Để dễ dàng thực hiện các phép toán ta lưu mảng theo thứ tự ngược lại với số,tức là các chữ số trong mảng lưu theo chiều từ trái sang phải: chữ số hàng đơn vị

là phần tử thứ nhất, chữ số hàng chục là phần tử thứ hai, …

Ví dụ: số X = 1965 thì mảng X sẽ là: (5,6,9,1,0,0,0…) tức là X[1] = 5; X[2] = 6;X[3] = 9; X[4] = 1; X[5] = 0,…

Dữ liệu vào: Gồm hai số nguyên lớn hoặc số nguyên lớn và số nguyên nhỏ (số

nhỏ là số có kiểu chuẩn: byte, integer, word, longint…), hai số cách nhau mộtdòng trống, mỗi số nguyên lớn có thể ghi trên nhiều dòng

Thủ thục đọc file dữ liệu vào gồm hai số nguyên lớn:

repeat readln(f,s); ma:=ma+length(s); until s='';

repeat readln(f,s); mb:=mb+length(s); until s='';

ma:=0; fillchar(a,sizeof(a),0); {a là số nguyên lớn}

repeat readln(f,s); ma:=ma+length(s); until s='';

close(f); reset(f); n:=ma;

Trang 5

Để so sánh hai số nguyên lớn a, b ta so sánh độ dài của hai số Nếu hai số có

độ dài bằng nhau thì so sánh từng chữ số của hai số Hàm cmp trả về giá trị 1nếu a lớn hơn b, trả về giá trị -1 nếu a nhỏ hơn b và trả về giá trị 0 nếu a bằng b

Function cmp(a,b:bigint):integer;

Var i:integer;

Begin

If ma>mb then begin cmp:=1; exit; end

Else if ma<mb then begin cmp:=-1; exit; end

Else

For i:= ma downto 1 do

If a[i]>b[i] then begin cmp:=1; exit; end

Else if a[i]<b[i] then begin cmp:=-1; exit; end;

- nho:=t div 10;

- Tong[i]:=t mod 10;

Lưu ý: nho có thể lớn hơn 10.

Procedure cong( a:bigint; num:longint; var

ma:=ma+1;

tong[ma]:=nho mod 10; nho:=nho div 10;

Trang 6

Chú ý: Trong Turbo Pascal kết quả trả lại của hàm là các kiểu cơ sở như: số

nguyên, số thực, kí tự, và kiểu xâu Nếu muốn trả lại kết quả là kiểu cấu trúcnhư mảng thì chỉ có cách dùng tham biến Nhưng Free Pascal cho phép kết quảcủa hàm có thể là kiểu cấu trúc Như vậy nếu viết trong Free Pascal ta có thểthay thủ tục cộng bằng hàm cộng hai số

if ma >=mb then begin max:=ma; for

i:=mb+1 to ma do b[i]:=0; end

else begin max:=mb; for i:=ma+1 to

mb do a[i]:=0; end;

t:=0; fillchar(tong,sizeof(tong),0);

for i:=1 to max do

begin t:=t+a[i]+b[i];

- Trường hợp a>b thì thực hiện a trừ cho b

- Trường hợp a<b thì lấy b trừ cho a sau đó thêm dấu âm đằng trước

Procedure tru (a,b:bigint; var

hieu:bigint);

var i,nho:longint;

begin

if ma >=mb then begin max:=ma;

for i:=mb+1 to ma do b[i]:=0; end

else begin max:=mb; for i:=ma+1

to mb do a[i]:=0; end;

nho:=0;

begin nho:=a[i]-b[i]-nho;

if nho<0 then begin hieu[i]:=10+nho; nho:=1; end

else begin hieu[i]:=nho; nho:=0; end;

end;

{xoa so 0 o dau}

while (max>1) and (kq[max]=0)

Trang 7

for i:=1 to max do do max:=max-1;

end;

1.2.5 Phép nhân một số lớn với một số nhỏ

Thuật toán: Nhân một số lớn x với số nhỏ num Ta không cần quan tâm num có

bao nhiêu chữ số cứ coi nó chỉ là số có một chữ số và nhân với từng chữ số của

số lớn x từ phải sang trái, nhớ có thể lớn

procedure nhan (x:bigint; num:longint;

1.2.6 Phép nhân hai số nguyên lớn

Thuật toán: Như phép nhân thông thường đã học và thực hiện trên giấy

Ví dụ:

procedure

procedure nhan2so(a,b:bigint; var tich:bigint); {tích hai số lớn}

var x:bigint; j,k,l:integer;

Theo trên ta thấy việc nhân hai số gồm hai thao tác:

Thao tác 1: Thực hiện việc nhân mỗi chữ số (từ phải sang

trái cho đến hết) của số thứ hai với số thứ nhất

Thao tác 2: Thực hiện phép cộng tất cả các số vừa tính

Trang 8

end;

end;

1.2.7 Phép chia một số nguyên lớn cho một số nguyên nhỏ (lấy phần thương nguyên (div) và dư (mod))

Thuật toán chia một số lớn cho một số nhỏ thao tác từ trái qua phải, mỗi lần

hạ một phần tử xuống, gộp vào biến nhớ, thực hiện phép chia trực tiếp (vì sốchia là một số nhỏ)

Procedure chia( a:bigint;

if nho<num then begin i:=i+1;

thuong[i]:=nho div num; end;

{Xóa số 0 ở đầu của số thuong}

while (thuong[1]=0) and (max>1) do begin

for j:=1 to max-1 do thuong[j]:=thuong[j+1];

liên tiếp từng đoạn của số bị chia (từ trái sang phải) cho số chia:

 Cắt lần lượt từng đoạn của số bị chia tính từ bên trái (có cộng thêmphần dư của các bước trung gian)

 Đem chia các đoạn đó cho số chia bằng phép toán trừ

 Thương tìm được là dãy các số Dãy số này là kết quả của phép chiacác đoạn cho số chia (được phát triển dần về phía bên phải)

 Phần dư của phép chia chính là đoạn còn lại không thể chia được nữa

procedure chia(a,b:bigint;var thuong,du:bigint);

Trang 9

m:=i; {m là độ dài của thuong}

{Xóa số 0 ở đầu của số thuong}

while (thuong [1]=0) and (m>1) do

2.1 Bài toán 1 Tính giai thừa

Hãy tính N! (N<=2000)

Thuật toán:N! = 1*2*…*N Vì N rất lớn, như vậy khi nhân các giá trị có thể rất

lớn, ta không thể dùng các kiểu số có sẵn để lưu trữ mà phải dùng xâu hoặcmảng để lưu

Để tính giá trị của biểu thức ta phải thực hiện thao tác: nhân một số lớn với số

inc(max);

tich[max]:=nho mod 10;

Trang 10

bigint=array[1 maxn] of chuso;

var kq,tich:bigint; max,n,i:integer;

procedure nhan(x:bigint; num:longint;

2.2 Bài toán 2 (Đề Bảng C Tin học trẻ không chuyên toàn quốc năm 2004)

Xét dãy số nguyên gồm n số hạng a1, a2, …, an (n được gọi là độ dài của dãy)được xác định như sau:

a1 = a2 = a3 =1; an = an-3 +an-1 với n>3

Yêu cầu: Hãy xác định độ dài lớn nhất của dãy thỏa mãn mọi giá trị số hạng đềunhỏ hơn hay bằng một giá trị nguyên k cho trước

Dữ liệu vào: từ file văn bản DAYSO.INP gồm một dòng chứa không quá 255

chữ số viết liền nhau (không có các số 0 vô nghĩa ở đầu) biểu diễn giá trị k

Kết quả: Ghi ra file văn bản DAYSO.OUT độ dài lớn nhất của dãy tìm được.

Trang 11

assign(f,fi); reset(f); assign(g,go); rewrite(g);

end;

{================================================} procedure Closef;

if p<l then begin Lonhon:=false; exit; end

else if p>l then begin Lonhon:=true; exit; end

else

for i:=p downto 1 do

Trang 12

if k[i]>d[i] then begin lonhon:=false; exit; end

else if k[i]<d[i] then begin lonhon:=true; exit; end;

lonhon:=false;

end;

{===============================================} procedure Main;

2.3 Bài toán 3 (Đề thi OLIMPIC Tin học sinh viên Việt Nam 2005)

Một hệ thống giao thông gồm N nút (các nút được đánh số từ 1 đến N),trong đó bất kỳ hai nút nào cũng có đoạn đường hai chiều nối chúng Ta gọiđường đi giữa hai nút là dãy các đoạn đường kế tiếp nhau, bắt đầu từ một nút vàkết thúc tại nút kia, trong đó không có nút nào trên đường đi được lặp lại

Yêu cầu: Cần đếm tất cả các đường đi khác nhau giữa hai nút bất kỳ của mạnggiao thông đã cho

Ví dụ: Với hệ thống giao thông 4 nút trong hình dưới đây, ta có 5 đường đi nốigiữa hai nút tô đen

Trang 13

 Ta dễ thấy rằng: tổng các đường đi

từ 2 đỉnh bất kì là tổng các đường đi có độ dài bằng 1, các đường đi có độdài bằng 2, các đường đi có độ dài bằng 3, …, các đường đi có độ dàibằng n-1 Cũng chính là tổng các đường đi không đi qua đỉnh trung giannào, đi qua 1 đỉnh trung gian, qua 2 đỉnh trung gian, …, qua n-2 đỉnhtrung gian

 Tổng các đường đi không đi qua đỉnh trung gian nào là 1 (chính là đườngnối trực tiếp 2 đỉnh đó) Tổng các đường đi đi qua 1 đỉnh trung gian là sốcách chọn có thứ tự 1 đỉnh trong số n-2 đỉnh còn lại (A1 n-2), tổng cácđường đi đi qua 2 đỉnh trung gian là số cách chọn có thứ tự 2 đỉnh trong

số n-2 đỉnh còn lại (A2 n-2), tổng các đường đi qua 3 đỉnh trung gian là sốcách chọn có thứ tự 3 đỉnh trên n-2 đỉnh còn lại (A3 n-2), …, tổng cácđường đi qua n-2 đỉnh trung gian là số cách chọn có thứ tự n-2 đỉnh trênn-2 đỉnh còn lại (An-2 n-2).

 Qua công thức trên ta thấy S là một số rất lớn (với N = 1000 thì S có tới

2563 chữ số), không có kiểu số nào có thể lưu trữ được, ta phải sử dụngkiểu dữ liệu khác Tốt nhất trong trường hợp này ta nên sử dụng mảngkiểu longint, với mỗi phần tử mảng sẽ lưu 1 số có 6 chữ số của chữ số S

 Để đơn giản trong xử lý ta nên lưu ngược, a[1] sẽ chứa 6 chữ số cuối cùngcủa S, a[2] sẽ chứa 6 chữ số tiếp theo, …

PCOUNT.INP PCOUNT.OUT

S:=1;

For i:=1 to n-2 do Begin

S:= S*i;

S:=S+1;

End;

Trang 14

Ví dụ: S = 1234031809283756

Ta có mảng A như sau: a[1] = 283756; a[2] = 031809; a[3] = 001234.Nhưng thực tế a[2] = 31809; a[3] = 1234 (loại bỏ các số 0 ở đầu trái), vậy khighi kết quả ra file ta phải xử lý thêm chỗ này để đạt được kết quả đúng (thêm 0vào trước cho đủ 6 chữ số rồi mới ghi ra file kết quả)

s:string; f:text; ok:boolean;

a:array[1 500] of longint;{mang chua

if n>1 then Begin str(a[m],s); write(f,s);

For i:=m-1 downto 1 do Begin

str(a[i],s);

if i<>6 then Begin l:=length(s);

while l<>6 do Begin insert('0',s,1); l:=l+1; End;

End;

write(f,s);

End;

End else Write(f,'0');

close(f);

End;

BEGIN Khoi_tao;

Thuc_hien;

In_ra;

END.

Trang 15

2.4 Bài toán 4 (Đề thi OLP 2004)

Gọi X là tập tất cả các xâu nhị phân không có 2 bit 1 liền nhau Các xâuđược đánh thứ tự theo trình tự được sinh ra (từ nhỏ

đến lớn, bit 0 đứng trước bit 1) Chẳng hạn với n=5 ta

có các xâu sau:

Bài toán đặt ra: Hãy xác định xâu nhị phân n bit ứng

với số thứ tự m cho trước Hạn chế: n<=200

Dữ liệu: Nhập từ file văn bản Nhiphan.Inp gồm:

 Dòng đầu tiên là số nguyên dương n (n<= 200)

 Dòng thứ hai là số thứ tự m

Kết quả: Ghi ra file Nhiphan.Out xâu nhị phân n bit

tương ứng với số thứ tự m Ví dụ

Thuật toán

 Gọi L[k] là số các xâu nhị phân như

vậy có k bit Nếu bit thứ k của nó là bit

0 thì k-1 bit còn lại là tự do (tức là ta có

L[k-1] dãy) Nếu bit thứ k của nó là bit

1 thì bit k-1 phải là 0, và k-2 bit còn lại

tự do Vậy ta có: L[k]=L[k-1]+L[k-2] Trong đó L[1] = 2, L[2] = 3

 Từ công thức đó ta xác định được số các xâu có n bit Để xác định xâu nhị

phân n bit có thứ tự m cho trước ta có nhận xét: nếu m>L[n-1] thì nhất định bit thứ n phải là 1 Xâu n-1 bit còn lại sẽ có thứ tự là m-L[n-1] Ngược lại thì bit thứ n là bit 0 và xâu n-1 bit còn lại có thứ tự là m.

 Do đó ta có thể làm như sau:

For i:= n downto 1 do

If m<=L[i-1] then x[i]:=0 Else

x[i]:=1; m:= m – L[i-1];

1234567

00000000010001000100001010100001001

Nhiphan.inp Nhiphan.out

55

00101

Trang 16

End;

 Tuy nhiên n có thể bằng 200 nên m và các giá trị L[i] có thể xấp xỉ 2200tức là cỡ 1070 (vì 210 xấp xỉ 103) Ta không thể dùng các kiểu số có sẵn màphải sử dụng kiếu số lớn và các phép toán trên số lớn

var i,t:byte;

begin

if na>=nb then begin max:=na; for i:=nb+1 to na do b[i]:=0; end

else begin max:=nb; for i:=na+1 to nb do a[i]:=0; end;

Trang 17

end;

if t>0 then begin max:=max+1; kq[max]:=t; end;

end;

{===============================================} Function sosanh(var a,b:bigint; na,nb:byte):boolean;

var i:byte;

Begin

sosanh:=true;

if na<nb then exit

else if na>nb then begin sosanh:=false; exit; end

else

for i:=na downto 1 do

if a[i]<b[i] then exit

else if a[i]>b[i] then begin sosanh:=false; exit; end;

End;

{===============================================} procedure tru(var a,b:bigint; var na,nb:byte);

var i,nho,max:longint;

begin

if na >=nb then begin max:=na; for i:=nb+1 to na do b[i]:=0; end

else begin max:=nb; for i:=na+1 to nb do a[i]:=0; end;

var i,j:integer;

Begin

For i:=3 to n do cong(L[i-1],l[i-2],L[i],cd[i-1],cd[i-2],cd[i]);

Ngày đăng: 21/10/2019, 20:28

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w