1. Trang chủ
  2. » Công Nghệ Thông Tin

Tính toán trước khi lập trình

5 434 2
Tài liệu đã được kiểm tra trùng lặp

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

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Tính toán trước khi lập trình
Tác giả Nguyễn Duy Hàm
Người hướng dẫn Thầy Nguyễn Xuân Huy
Trường học Đại học Khoa học Tự nhiên
Chuyên ngành Tin học
Thể loại bài viết
Năm xuất bản 2005
Thành phố TP.Hồ Chí Minh
Định dạng
Số trang 5
Dung lượng 49,5 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Tính toán trước khi lập trình

Trang 1

Tính toán trước khi lập trình

Nguyễn Duy Hàm

Trong một bài viết trên tạp chí Tin học và Nhà trường Thầy Nguyễn Xuân Huy đã nói về vấn đề đặt bút tính toán trước khi lập trình, Thầy đề cập đến bài toán đếm số ô vuông đơn

vị bị cắt bởi 1 đường chéo của 1 hình chữ nhật có kích thước nxm Qua đó chúng ta có thể phần nào hiểu được rằng việc tính toán, phân tích bài toán trước khi lập trình là vô cùng cần thiết, trong nhiều kì thi học sinh, sinh viên giỏi tin học có những bài toán tưởng chừng rất dễ, song nếu không được tiền xử lý tốt thì chỉ có thể vượt qua một vài test dễ ban đầu của BGK mà thôi Lần này tôi cũng xin mạn phép được bàn về cùng vấn đề trong một bài toán khác, đó là một bài số 3 trong đề thi của khối chuyên tại kì thi OLIMPIC Tin học Sinh viên Việt Nam 2005 tại Đại học Khoa học Tự nhiên TP.Hồ Chí Minh vừa qua

Bài toán

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ạng giao thông

đã cho

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

(xem hình 2)

Dữ liệu: Nhập từ file văn bản PCOUNT.INP gồm một số nguyên dương N (N

Kết quả: Ghi ra file PCOUNT.OUT gồm 1 dòng chứa số các đường đi khác nhau đếm

được

Ví dụ:

Trang 2

Khi đọc bài toán này không ít bạn đã rất loay hoay, không biết phải làm thế nào, nhiều bạn

đã sử dụng ngay đệ quy quay lui để duyệt tất cả các đường đi có thể từ đỉnh đầu đến đỉnh cuối trên 1 đồ thị ngầm định được xây dựng, vì cứ nói đến hệ thống giao thông là nhiều người nghĩ ngay tới cấu trúc đồ thị, với cách làm này chương trình không thể vượt qua test với n>15! (cần chú ý là bài toán này hạn chế thời gian chạy là 1 giây), nên việc duyệt như trên sẽ là một giải pháp khó có thể chấp nhận Ta hãy cùng nhau phân tích bài toán

Cách giải quyết

Thuật toán:

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 =1, các đường đi có độ dài =2, các đường đi có độ dài =3…,các đường đi có độ dài n-1 Cũng chính là tổng các đường đi không đi qua đỉnh trung gian nào, đi qua 1 đỉnh trung gian, qua

2 đỉnh trung gian,…qua n-2 đỉnh trung gian

Tổng các đường đi không đi qua đỉnh trung gian nào là 1 (chính là đường nối trược tiếp 2 dỉ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 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ó tứ tự 3 đỉnh trên n-2 đỉnh còn lại (A3

n-2)

Như vậy:

S=1+A1

n-2+ A2

n-2 + A3 n-2+…+An-2

n-2.(1) (1)=1+(n-2)+(n-2)(n-3)+(n-2)(n-3)(n-4)+…+(n-2)!(2)

(2)=1+(n-2)[1+(n-3)[1+(n-4)[…[1+1]…]]].(3)

(3)=(( (1+1)2+1)3+1)4+1)5+1)…(n-3)+1)(n-2)+1(4)

Như vậy từ công thức (4) ta có thuật toán theo đoạn mã sau:

s:=1;

For i:=1 to n-2 do

Begin

s:=s*i;

s:=s+1;

End;

Cấu trúc dữ liệu:

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ụng kiểu dữ liệu khác Tốt nhất trong

trường hợp này ta nên sử dụng mảng kiể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

Trang 3

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

Ví dụ s=1234031809283756

Thì ta có mảng A như sau: a[1] = 283756; a[2]=031809; a[3]=001234;

Nhưng thực tế a[2] = 31809 và a[3]=1234(loại bỏ các số 0 ở đầu trái), vậy khi ghi kết quả

ra file ta phải xử lý thêm chỗ này để đạt được kết quả đúng (thêm 0 vào trước cho đủ 6 chữ

số rồi mới ghi ra file) Bây giờ vấn đề còn lại là lập trình Chúng ta cùng theo dõi đoạn mã sau:

Chương trình

Const stout='PCOUNT.OUT';

stinp='PCOUNT.INP';

k=1000000;

d=6;

Var i,j,n,m,l,nho:longint;

s:string;

f:text;

ok:boolean;

a:array[1 500]of longint;//mảng chứa dãy số

Procedure Khoi_tao;

Begin

assign(f,stinp);

reset(f);

read(f,n);

close(f);

a[1]:=1;m:=1;

End;

Procedure Thuc_hien;

Begin

for i:=1 to n-2 do

begin

nho:=0;

for j:= 1 to m do

begin

nho:=nhơa[j]*i;

a[j]:=nho mod k;

nho:=nho div k ;

end;

if nho>0 then

begin

m:=m+1;

a[m]:=nho;

Trang 4

nho:=1;ok:=true;j:=0;

while ok do

begin

j:=j+1;

nho:=a[j]+nho;

a[j]:=nho mod k;

nho:=nho div k;

if nho=0 then ok:=false;

end;

if j>m then m:=j;

end;

end;

Procedure In_ra;

Begin

assign(f,stout);

rewrite(f);

if n>1 then

begin

for i:=m downto 1 do

begin

str(a[i],s);

if i< br>begin

l:=length(s);

while l< br> 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

Chú ý khi lập trình

- Không sử dụng các thủ tục inc(),dec() làm chậm chương trình

Trang 5

- Trong chương trình có đoạn mã thêm số 0 vào trước các phần tử của mảng trước khi ghi lên file, không nên viết như sau mặc dù nó gọn hơn:

While length(s) < d do insert(‘0’,s,1); vì nó sẽ gọi hàm length(s) liên tục mỗi khi kiểm tra làm chậm chương trình của chúng ta

Kết luận

Cuối cùng ta thấy rằng bài toán này không phức tạp, không đòi hỏi phải tư duy thuật toán cao siêu, chỉ cần nắm vững kiến thức toán tổ hợp, biết cách xử lý trên số lớn, cùng với việc tính toán phân tích kĩ bài toán trước để tìm ra công thức đơn giản nhất, sao cho phép toán thực hiện là ít nhất sẽ đảm bảo chương trình chạy nhanh nhất!

Qua phần trình bày trên ta có thể thấy được sự liên quan mật thiết giữa toán học và tin học như thế nào, việc tính toán, phân tích kĩ bài toán, việc sử dụng thành thạo cấu trúc dữ liệu quan trọng như thế nào trong việc giải 1 bài toán trong tin học Mọi góp ý, trao đổi xin gửi

về duyhaman@yahoo.com Xin cảm ơn!

Ngày đăng: 11/09/2012, 15:49

HÌNH ẢNH LIÊN QUAN

Ví dụ: Với hệ thống giao thông 4 nút trong hình 1, ta có 5 đường đi nối giữa hai nút tô đen (xem hình 2). - Tính toán trước khi lập trình
d ụ: Với hệ thống giao thông 4 nút trong hình 1, ta có 5 đường đi nối giữa hai nút tô đen (xem hình 2) (Trang 1)
Tính toán trước khi lập trình - Tính toán trước khi lập trình
nh toán trước khi lập trình (Trang 1)

TỪ KHÓA LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm

w