Chương trình C# // C#

Một phần của tài liệu Các thuật toán sắp đặt (Trang 26 - 30)

// C# using System; using System.Collections.Generic; using System.Text; using System.IO; namespace SangTao2 { class BoBai {

const string fn = "bai.inp"; const int MN = 20;

static int[] a;

static int n; // so luong quan bai

static int k; // so luong quan bai tren tay

static int s; // so cho truoc trong khoang [1,n]; static int t;

static void Main(string[] args){ Doc(); XuLi();

Console.ReadLine(); }

static void Doc(){ int[] c =

Array.ConvertAll((File.ReadAllText(fn)).Split( new char[] { '\0', '\n', '\t', '\r', ' ' }, StringSplitOptions.RemoveEmptyEntries), new Converter<String, int>(int.Parse)); n = c[0]; // so luong quan bai

k = c[1]; // so luong quan bai tren tay s = c[2]; // so cho truoc s = c[2]; // so cho truoc

a = new int[n + 1];

Array.Clear(a, 0, a.Length); t = 0;

for (int i = 3; i < c.Length; ++i){ a[c[i]] = 1; t += c[i];

}; } }

static void XuLi(){ t %= n; s %= n;

int b = (t >= s) ? t - s : n - (s - t); if (b == 0) { Ket(0, 0, 0); return; }

// Sua t: giam b don vi hoac tang n-b don vi if (a[b] == 1) { // quan b co tren tay Ket(1, -b, 0); // bo quan b

return; }

if (a[n - b] == 0) { // quan n-b co tren ban Ket(1, n - b, 0); // lay quan n-b

return; }

// Quan b tren ban, quan n-b trên tay int u = b, v = 0;

do { v = u; u = (u + b) % n; } while(a[u] == 0); Ket(2, -u, v); // bo quan u, lay quan v

}

static void Ket(int c, int u, int v) { switch (c){

case 0: Console.WriteLine(c); break;

case 1: Console.WriteLine(c + ": " + u); break; case 2: Console.WriteLine(c + ": "+u+" , "+v); break; } } } // Bo Bai } // SangTao2 4.7 Thuận thế Dijkstra E. Cho hoán vị a = (a1,a2,...,aN) của N số nguyên dương đầu tiên 1,2,...,N. Một thuận thế của a là dãy b = (b1,b2,...,bN) trong đó bi là số lượng các phần tử nhỏ thua ai và đứng trước ai, bi = ||{aj | aj < ai, j < i}||. Biết trước N, 2 N 1000.

a) Cho một hoán vị a, tính thuận thế b của a. b) Cho thuận thế b, tìm hóan vị a.

c) Mọi thuận thế đều có phần tử đầu tiên (trái nhất) là 0 nên ta có thể bỏ phần tử này. Ngoài ra, nếu trong thuận thế còn có phần tử 0 nữa ta bỏ thêm 1 phần tử 0 để thu được một dãy có M = N-1 hoặc M = N- 2 phần tử và gọi dãy này là thuận thế thu gọn c. Cho một thuận thế thu gọn. Hãy tìm hoán vị nhỏ nhất theo trật tự từ điển sinh ra thuận thế thu gọn này.

Thí dụ, với N = 5,

a) Cho a = (2,5,1,4,3) ta tính được b = (0,1,0,2,2), b) Cho b = (0,1,0,2,2) ta tìm được a = (2,5,1,4,3), (adsbygoogle = window.adsbygoogle || []).push({});

c) Cho thuận thế thu gọn c = (1,2,2), N = 5, ta tìm được a = (2,3,5,4,1).

Để ý rằng hai hoán vị (2,5,1,4,3) và (2,3,5,4,1) cùng sinh ra thuận thế thu gọn (1,2,2), nhưng hoán vị (2,3,5,4,1) nhỏ hơn.

Dữ liệu vào: text file THUANTHE.INP Dòng đầu tiên: N

Từ dòng thứ hai trở đi: N phần tử của hoán vị a. Dòng tiếp theo: M

Trên các dòng tiếp theo: M phần tử của thuận thế thu gọn. Dữ liệu trên cùng một dòng cách nhau qua dấu cách.

Dữ liệu ra: Hiển thị trên màn hình theo trật tự sau: Câu a: Cho hoán vị a, tìm thuận thế b. Câu b: Cho thuận thế b, tìm hoán vị a.

Câu c: Cho thuận thế thu gọn c tìm hoán vị nhỏ nhất a.

Thuật toán

Việc xác định thuận thế b từ hoán vị a là dễ dàng. Hai câu b và c là hơi khó. Chúng ta sẽ sử dụng kỹ thuật đối xứng để trình bày một thuật toán do Dijkstra đề xuất. Theo thuật toán này thì thủ tục cho câu a và b là đối xứng nhau. Thuật toán tiến hành xử lý tại chỗ, nghĩa là không sử dụng mảng phụ mà trực tiếp biến đổi hoán vị a thành thuận thế lưu luôn trong a và ngược lại.

Trước hết ta nhận xét rằng với hoán vị đơn vị e = (1,2,...,N) thì có đúng ei phần tử không lớn hơn ei và không đứng sau phần tử ei, i = 1..N. Vậy, nếu trong một hoán vị a mà ta thấy một phần tử aj ai và j  i thì ta khẳng định rằng chỉ còn đúng aj-1 phần tử không lớn hơn aj và không đứng sau phần tử aj.

Ta khai báo các biến x, y, a là các mảng để chứa các hoán vị và thuận thế:

const MN = 1000;

type mi1 = array[0..MN] of integer; var x,y,a: mi1;

procedure HoanViThuanThe(var a: mi1;n: integer); var i,j: integer;

begin

for i := n downto 1 do for j:=1 to i do

if (a[j] >= a[i]) then dec(a[j]); end;

Để thu được hoán vị a từ thuận thế a ta chỉ cần viết thủ tục xử lý theo chiều ngược lại. Hai thủ tục như vậy gọi là đối xứng nhau.

procedure ThuanTheHoanVi(var a: mi1;n: integer); var i,j: integer;

begin

for i := 1 to n do

for j := i downto 1 do

if (a[j] >= a[i]) then inc(a[j]); end;

Hai thủ tục này đều có độ phức tạp N2.

Câu c được giải như sau. trước hết thêm một số 0 vào đầu trái của dữ liệu vào a. Sau đó xét hiệu N- M. Nếu N-M=1 thì chứng tỏ thuận thế thu gọn a chỉ khuyết một số 0. Ta chỉ việc gọi thủ tục

ThuanTheHoanVi(a,N) là thu được kết quả. Trường hợp N-M=2 thì ta phải bù thêm một số 0 nữa vào

một vị trí nào đó trong a. Ta lần lượt đặt số 0 này vào đầu phải (vị trí N) rồi chuyển dần nó về đầu trái, mỗi lần một vị trí và gọi thủ tục ThuanTheHoanVi để sinh ra một dãy a[1..N] sau đó kiểm tra xem dãy này có phải là hoán vị của 1..N hay không. Nếu đúng, ta dừng thuật toán và cho ra kết quả. Để kiểm tra một dãy a[1..N] có phải là một hoán vị của 1..N ta sử dụng một mảng d[1..N] đánh dấu xem mỗi phần tử a[i] có xuất hiện đúng 1 lần hay không. Tuy nhiên trước đó ta phải kiểm tra điều kiện 1  a[i]  N để đảm bảo rằng a[i] nằm trong giới hạn của chỉ số mảng d.

procedure ThuanTheThuGon(var a: mi1; n,m: integer); var b: mi1; i: integer; begin move(a[1],a[2],m*sizeof(integer)); a[1] := 0; inc(m); if (n = m) then begin ThuanTheHoanVi(a,n); exit; end; b := a; for i := n downto 2 do begin

{ Them 0 tai vi tri i } a := b;

move(a[i],a[i+1],(n-i)*sizeof(integer)); a[i] := 0; (adsbygoogle = window.adsbygoogle || []).push({});

ThuanTheHoanVi(a,n);

if LaHoanVi(a,n) then exit; end;

end;

function LaHoanVi(var a: mi1; n: integer): Boolean; var d: mi1; i: integer; begin LaHoanVi := false; fillchar(d,sizeof(d),0); for i := 1 to n do

begin

if (a[i] < 1) or (a[i] > n) then exit; if (d[a[i]] = 1) then exit;

d[a[i]] := 1; end; LaHoanVi := true; end; Chương trình C# using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System; namespace SangTao2 { class ThuanThe {

const string fn = "thuanthe.inp"; const int MN = 1001;

static int[] a = new int[MN]; static int[] c = new int[MN]; static int n; // 1..n

static int m; // so luong phan tu trong thuan the thu gon static void Main(string[] args){

Doc();

Console.WriteLine("\n n = " + n + " m = " + m); Console.WriteLine("\n Cho Hoan vi: ");

Show(a, n);

HoanViThuanThe(a);

Console.WriteLine("\n Tim Thuan the: "); Show(a, n);

Console.WriteLine("\n Cho Thuan the: "); Show(a, n);

ThuanTheHoanVi(a);

Console.WriteLine("\n Tim Hoan vi: "); Show(a, n);

Console.WriteLine("\n Cho Thuan the Thu gon: "); Show(c,m);

ThuanTheThuGon(c);

Console.WriteLine("\n Tim Hoan vi: "); Show(c, n);

Console.ReadLine(); }

static void Doc(){ int[] v =

Array.ConvertAll((File.ReadAllText(fn)).Split( new char[] { '\0', '\n', '\t', '\r', ' ' }, StringSplitOptions.RemoveEmptyEntries), new Converter<String, int>(int.Parse)); int i = 0;

n = v[i++];

for (int j = 1; j <= n; ++j) a[j] = v[i++]; m = v[i++];

for (int j = 1; j <= m; ++j) c[j] = v[i++]; }

static void HoanViThuanThe(int[] a){ for (int i = n; i > 0; --i)

for (int j = 1; j <= i; ++j) if (a[j] >= a[i]) --a[j]; }

static void ThuanTheHoanVi(int[] a){ for (int i = 1; i <= n; ++i) for (int j = i; j > 0; --j) if (a[j] >= a[i]) ++a[j]; } (adsbygoogle = window.adsbygoogle || []).push({});

static void ThuanTheThuGon(int[] c){ Array.Copy(c, 1, c, 2, m);

c[1] = 0; ++m;

if (m == n) { ThuanTheHoanVi(c); return; } int [] b = new int [n+1];

Array.Copy(c,1,b,1,m);

for (int i = n; i >= 2 ; --i){ Array.Copy(b,1,c,1,i-1); Array.Copy(b, i, c, i + 1, m - i + 1); c[i] = 0; ThuanTheHoanVi(c); if (LaHoanVi(c)) return; } }

static bool LaHoanVi(int[] c){ int[] d = new int[n + 1]; Array.Clear(d,0,d.Length); for (int i = 1; i <= n; ++i) {

if (c[i] < 1 || c[i] > n) return false; if (d[c[i]] > 0) return false;

d[c[i]] = 1; }

return true; }

static void Show(int[] a, int n){ for (int i = 1; i <= n; ++i) Console.Write(a[i] + " "); }

} // ThuanThe } // SangTao2

Một phần của tài liệu Các thuật toán sắp đặt (Trang 26 - 30)