Một số thuật toán có nhiều ứng dụng
Một thuật toán có nhiều ứng dụngXuân PhongTa xét bài toán sau:Bài toán 1: (Số sát sau) cho số tự nhiên a có n chữsố. Hãy hoán vị các chữ số trong a để được số sát sau số a. Dữ liệu vào ghi trong tệp văn bản SOSATSAU.INP: dòng đầu tiênlà giá trị n, từ dòng thứ hai trở đi là các chữ số của a.Dữ liệu ra là số sát sau của số a và được ghi trong tệpSOSATSAU.OUT. Nếu vô nghiệm thì ghi chữ số 0. Giới hạn của n là 1000.Thí dụ:SOSATSAU.INP 6526431SOSATSAU.OUT 531246Bài giải:Trước hết ta đọc dữ liệu từ tệp SOSATSAU.INP vào biến n và mảngký tự a[1 n].procedure doc;var i : integer;c: char;beginassign(f.fn); reset(f);readln(f,n); i:=0;while not eof(f) dobeginread(f,c); if(c>='0') and (c<='9') thenbegininc(i); a[i]:=c;end;end;close(f);end;Các hằng và biến được khai báo như sau:const mn=1000;fn = 'sosatsau.inp';gn = 'sosatsau.out';var a: array[0 mn] of char;n: interger;f,g: text;Chú ý rằng số a có thể có đến 1000 chữ số do đó người ta cóthể viết trên nhiều dòng cho nen thủ tục đọc phải nhận biết đượccác chữ số thông qua dong lệnh:if (c>='0') and (c<='9') then .Thuật toán tìm số sát sau: Để tìm số sát sau của a,ta sửa tại chỗ mảng a theo các bước sau:1. Tìm điểm gãy: Duyệt ngược mảng a để tìm vị tríi đầu tiên thoả mãn a[i] < a[i+1].2. Xét điều kiện kết thúc: Nếu không tìm được chỉsố i như trên, tức là các chữ số của số đã cho xếp theo thứ tự giảmdần do đó a chính là số lớn nhất, sau nó không còn số nào có thểnhận được bằng một phép hoán vị được nữa. Bài toán vô nghịêm:dưng thuật toán.3. Tìm điểm vượt: Ta xét trường tồn tại i trong khoảng1 n để a[i]a[i].4. Hoán vị: Hoán vị a[i] và a[j]. 5. Lật: Lật ngược đoạn a[i+1 n] sẽ thu được số cầntìm.Với thí dụ đã cho, n=6, a[1 6]=526431 ta thực hiện như sau:1. Tìm điểm gãy: Duyệt ngược mảng a ta tìm đượci=2; a[2]=2 < a[3]=6.2. Xét điều kiện kết thúc: Do tìm được chỉ số inên nghiệm của bài toán có thể tìm được từ bước 3 trở đi.3. Tìm điểm vượt: Ta duyệt ngược mảng a lầnthứ hai tìm được j=5, a[5]=3>a[2]=2.4. Hoán vị: Hoán vị a[2] và a[5] ta thu được 536421.5. Lật: Lật ngược đoạn a[2 6] sẽ thu được a=531246.Ta viết hàm Next kiểu Boolean cho ra giá trị True nếu có số sát sau,ngược lại hàm cho ra giá trị False. Để việc duyệt không vượt rangoài giới hạn mảng ta dùng phần tử a[0] làm lính canh. Ta gán giátrị cho a[0] nhỏ hơn ký tự '0':a[0]:=pred('0');Hàm Pred(c) cho ta giá trị sát trước giá trị c. Chương trìnhdưới đây khá gọn và không đòi hỏi giải thích thêm.user crt;const mn=1000;fn='sosatsau.inp'; gn='sosatsau.out';var a: array[0 mn] of char;n: integer; f,g: text;procedure doc; var i : integer;c: char;beginassign(f.fn); reset(f); readln(f,n); i:=0;while not eof(f) dobeginread(f,c);if(c>='0') and (c<='9') thenbegininc(i); a[i]:=c;end;end;close(f);end;function nex: Boolean;var i,j: integer;tg: char;beginnext: false; i:=n-1;{Duyet nguoc lan thu nhat tim diem gay}while a[i]>=a[i-1] dodec(i);if i=0 then exit;{Duyet nguoc lan hai tim diem vuot}j:=n;while a[j]<=a[i] do dec(j); {Hoan vi a[i] va a[j]}tg:=a[i]; a[i]:=a[j];a[j]:=tg; inc(i);{Lat doan a[i n]}j:=n;while i< begin> tg:=a[i]; a[i]:=a[j];a[j]:=tg; inc(i);dec(j); end;next:=true;end;procedure Ghi;{Ghi ket qua vao tep}var i: integer;beginfor i:=1 to n dowrite(g,a[i]);writeln(g);end;procedure BaiLam;begindoc; a[0]:=pred('0');assign(g,gn); rewrite(g); if next then ghielse writeln(g,'0');close(g);end;BEGINBaiLam;END.Du lieu Test:6526431Ket qua du kien:531246Dưới đây là một số ứng dụng của hàm Next.Bài tốn 2: (Hốn vị, Đề thi Olympic tin học Mascva,1980) sinh tồn bộ các hốn vị của day 1 n theo trật tự tăngdần. Giới hạn của n là 9. Thí dụ, với n=3 chương trình phải sinhđược 6 dãy: 123, 132, 213, 231, 312, 321.Bài giải:Ta xuất phát từ hốn vị đơn vị, mỗi lần gọi hàm Next ta thuđược hốn vị sát sau hốn vị trước. Khi hàm Next nhận giá trịFalse tức là ta đã đạt tới hỗn vị lớn nhất.procedure BaiLam2;beginKhoiTri; a[0]:=pred('0');assign(g,gn); rewrite(g);repeatghi; until not Next;close(g);end;Thủ tục KhoiTri sẽ như sau:procedure KhoiTri;var i: integer;begina[1]:='1';for i:=2 to n doa[i]:=succ(a[i-1]);end;Hàm succ(c) đối xứng với hàm pred, cho ta giá trị sát sau giá trịc.Bạn thử kiểm tra bài toán với n=3 như sau:BEGINn:=3;BaiLam2;END.Ta xét thêm một vài ứng dụng của hàm Next.Bài toán 3: (Tổ hợp) Sinh toàn bộ các tổ hợpchặp k của n phần tử. Giới hạn của n và k là 9. Thí dụ, với n=3, k=2chương trình phải sinh ra được 3 dãy: 23, 13, 12.Bài giải:Ta xuất phát từ tổ hợp gồm k phần tử cuối cùng. Muốn vậy ta gáncho k phần tử cuối cùng của mảng a là '1', n-k phần tử đầu tiênbằng '0'. Mỗi lần gọi hàm Next ta sẽ sinh ra số sát sau. Ta lấy kếtquả là i nếu a[i]='1'. Với thí dụ trên, n=3, k=2 ta khởi trị a='011'.Lần đầu tiên và sau mõi lần gọi Next ta thu dược: '011' cho ta 23'101' cho ta 13'110' cho ta 12.Bạn viết đoạn trình sau đây và ghép vào chương trìnhSOSATSAU.PAS để khảo sát:{Sinh cac to hop chap k cua n phan tu}Procedure KhoiTri3;var i: integer;beginfor i:=1 to n-k do a[i]:='0';for i:=n-k+1 to n do a[i]:='1';end;procedure Ghi3;var i:integer;beginfor i:=1 to n doif a[i]='1' then write(g,i);writeln(g);end;procedure BaiLam3;beginKhoiTri3; a[0]:pred('0');assign(g,gn); rewrite(g);repeat ghi3;until not Next;close(g);end;BEGINn:=3; k:=2;BaiLam3;END.Ket qua du kien:23 13 12 . Một thuật toán có nhiều ứng dụngXuân PhongTa xét bài toán sau:Bài toán 1: (Số sát sau) cho số tự nhiên a có n ch số. Hãy hoán vị các chữ số trong. text;Chú ý rằng số a có thể có đến 1000 chữ số do đó người ta cóthể viết trên nhiều dòng cho nen thủ tục đọc phải nhận biết đượccác chữ số thông qua dong