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

PHƯƠNG PHÁP THAM LAM

33 427 1
Tài liệu đã được kiểm tra trùng lặp

Đ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

Tiêu đề Phương pháp tham lam
Trường học Trường Đại Học Bách Khoa Hà Nội
Chuyên ngành Công Nghệ Thông Tin
Thể loại bài luận
Thành phố Hà Nội
Định dạng
Số trang 33
Dung lượng 820,54 KB

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

Nội dung

Băng nhạc Người ta cần ghi N bài hát, được mã số từ 1 đến N, vào một băng nhạc có thời lượng tính theo phút đủ chứa toàn bộ các bài đã cho.. Tính trung bình, các bài hát trong một ngày

Trang 1

Phương pháp tham lam gợi ý chúng ta tìm một trật tự hợp lí để duyệt dữ liệu nhằm đạt được mục tiêu một cách chắc chắn và nhanh chóng Thông thường, dữ liệu được duyệt theo một trong hai trật tự là tăng hoặc giảm dần theo một chỉ tiêu nào đó Một số bài toán đòi hỏi những dạng thức cải biên của hai dạng nói trên

Bài 5.1 Băng nhạc

Người ta cần ghi N bài hát, được mã số từ 1 đến N, vào một băng nhạc có thời lượng tính theo phút đủ chứa toàn bộ các bài đã cho Với mỗi bài hát ta biết thời lượng phát của bài đó Băng sẽ được lắp vào một máy phát nhạc đặt trong một siêu thị Khách hàng muốn nghe bài hát nào chỉ việc nhấn phím ứng với bài đó Để tìm và phát bài thứ i trên băng, máy xuất phát từ đầu cuộn băng, quay băng để bỏ qua i – 1 bài ghi trước bài đó Thời gian quay băng bỏ qua mỗi bài và thời gian phát bài đó được tính là như nhau Tính trung bình, các bài hát trong một ngày được khách hàng lựa chọn với số lần (tần suất) như nhau Hãy tìm cách ghi các bài trên băng sao cho tổng thời gian quay băng trong mỗi ngày là ít nhất

Dữ liệu vào được ghi trong tệp văn bản tên BANGNHAC.INP

- Dòng đầu tiên là số tự nhiên N cho biết số lượng bài hát

- Tiếp đến là N số nguyên dương thể hiện dung lượng tính theo phút của mỗi bài Mỗi đơn vị dữ liệu cách nhau qua dấu cách

Thí dụ dưới đây cho biết có N = 3 bài hát:

- Bài 1 phát trong thời gian 7 phút

- Bài 2 phát trong thời gian 2 phút

- Bài 3 phát trong thời gian 3 phút

Dữ liệu ra được ghi trong tệp văn bản

BANGNHAC.OUT theo dạng thức sau:

- N dòng đầu tiên thể hiện trật tự ghi bài hát trên băng: m ỗi dòng gồm hai số nguyên dương j và d cách nhau bởi dấu cách, trong đó j là mã số của bài hát cần ghi, d là thời

gian tìm và phát bài đó theo trật tự ghi này

- Dòng thứ n + 1 ghi tổng số thời gian quay băng nếu mỗi bài hát được phát một lần

trong ngày

Với thí dụ trên, kết quả thu được sẽ như sau:

- Cần ghi lần lượt trên băng các bài theo trật tự : bài 2, bài 3, bài 1;

Ta xét vài tình huống ghi băng để rút ra kết luận cần thiết

Trang 2

Trật tự ghi trên băng

(x, y, z)

Thời gian phát t(x) + t(y) + t(z); t(i): thời gian tìm và phát bài i ( ,  , ) (7) + (7 + 2) + (7 + 2 + 3) = 28 phút

Vậy phương án tối ưu sẽ là ( ,  , ): ghi bài 2 rồi đến bài 3, cuối cùng ghi bài

1 Tổng thời gian theo phương án này là 19 phút

Để có phương án tối ưu ta chỉ cần ghi băng theo trật tự tăng dần của thời lượng Bài toán được cho với giả thiết băng đủ lớn để ghi được toàn bộ các bài Dễ dàng sửa chương trình để vận dụng cho trường hợp dung lượng tăng hạn chế trong M phút Chương trình sắp xếp dữ liệu theo chỉ dẫn

Khoi tri mang chi dan id

quan li sap tang theo chi dan

Trang 3

procedure IDQuickSort(d,c: integer);

while a[id[j]] > m do dec(j);

if i <= j then begin

t := 0; {thoi gian tim va phat 1 bai}

tt := 0; {tong thoi gian cho n bai}

Trang 4

const string gn = "BangNhac.out";

static public Bang[] b;

static public int n = 0; // so bai hat

static void Main()

int t = 0; // tg tim va phat 1 bai

int tt = 0; // tong tg tim va phat n bai for (int i = 0; i < n; ++i)

// Doc lai file gn de kiem tra ket qua

static void Test() tự viết

static void Doc()

{

int [] a = Array.ConvertAll(

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

n = a[0];

Trang 5

b = new Bang[n];

for (int i = 1; i <= n; ++i)

b[i-1] = new Bang(a[i],i);

}

public struct Bang

{

public int len;// thoi luong

public int id; // so hieu 1,2,

public Bang(int t, int nn)

t = 0 và chỉ tắt máy sau khi đã hoàn thành đủ N công việc

Dữ liệu vào: tệp văn bản viec.inp:

Ý nghĩa: Cho biết có 4 việc với các thông tin sau:

- Việc thứ nhất phải nộp không muộn hơn thời điểm 1 (giờ) với tiền thưởng 15 (ngàn đồng);

- Việc thứ hai phải nộp không muộn hơn thời điểm 3 (giờ) với tiền thưởng 10 (ngàn đồng);

- Việc thứ ba phải nộp không muộn hơn thời điểm 5 (giờ) với tiền thưởng 100 (ngàn đồng);

- Việc thứ tư phải nộp không muộn hơn thời điểm 1 (giờ) với tiền thưởng 27 (ngàn đồng)

Dữ liệu ra: tệp văn bản viec.out:

- N dòng đầu tiên, dòng thứ t ghi một số tự nhiên i cho biết việc thứ i được làm trong giờ t

- Dòng cuối cùng ghi tổng số tiền thu được

Với thí dụ trên, tệp viec.out sẽ như sau:

Trang 6

thưởng 100;

- Giờ thứ 4 thực hiện việc 1;

- Tổng tiền thưởng thu được do đã hoàn thành đúng hạn

ba việc 4, 2 và 3 là 27 + 10 + 100 = 137

Thuật toán

Ta ưu tiên cho những việc có tiền thưởng cao, do đó ta sắp các việc giảm dần theo tiền thưởng Với mỗi việc k ta đã biết thời hạn giao nộp việc đó là h = t[k] Ta xét trục thời gian b Nếu giờ h trên trục đó đã bận do việc khác thì ta tìm từ thời điểm h trở về trước một thời điểm có thể thực hiện được việc k đó Nếu tìm được một thời điểm m như vậy, ta đánh dấu bằng mã số của việc đó trên trục thời gian b, b[m]:= k Sau khi xếp việc xong, có thể trên trục thời gian còn những thời điểm rỗi, ta dồn các việc đã xếp về phía trước nhằm thu được một lịch làm việc trù mật, tức là không có giờ trống Cuối cùng ta xếp tiếp những việc trước đó đã xét nhưng không xếp được Đây là những việc phải làm nhưng không thể nộp đúng hạn nên sẽ không có tiền thưởng Với thí dụ đã cho, N = 4, thời hạn giao nộp t = (1, 3, 5, 1) và tiền thưởng a = (15, 10, 100, 27) ta tính toán như sau:

- Khởi trị: trục thời gian với 5 thời điểm ứng với Tmax = 5 là thờ điểm muôn

nhất phải nộp kết quả, Tmax = max { thời hạn giao nộp }, b = (0, 0, 0, 0,0)

- Chọn việc 3 có tiền thưởng lớn nhất là 100 Xếp việc 3 với thời hạn t[3] = 5 vào

- Chọn nốt việc 2 có tiền thưởng 10 Xếp việc 2 với thời hạn t[2] = 3 vào h:

h[3] = 2

- Ta thu được h = (4, 0, 2, 0, 3)

- Dồn việc trên trục thời gian h, ta thu được h = (4, 2, 3, 0, 0)

- Xếp nốt việc phải làm mà không có thưởng, ta thu được h = (4, 2, 3, 1)

- Ca làm việc kéo dài đúng N = 4 giờ

- Nếu không muốn sắp giảm mảng tiền thưởng a theo chỉ dẫn ta có thể sắp song song a và id như mô tả trong chương trình

Trong chương trình dưới đây ta sử dụng mảng id với hai mục đích: id[i] = v > 0 cho biết việc v đứng thứ i trong dãy được sắp giảm theo giá trị tiền thưởng và việc v chưa được xếp id[i] = v < 0 cho biết việc v đã xếp xong trong lần duyệt đầu tiên

Trang 7

gn = 'viec.out'; {output file}

var

a,id,t: array[1 MN] of integer;

{a: tien thuong, t: thoi han giao nop}

{id: chi dan}

h: array[0 MN] of integer; {truc thoi gian}

N: integer; {so luong viec}

f,g: text;

M: integer; {so viec da xep}

tt: longint; {tong so tien thuong}

while a[id[j]] < m do dec(j);

Trang 8

{xep duoc viec v tai thoi diem k}

Don cac viec da xep trong h len phia truoc

va tinh tong tien thuong

M := i;

break;

end else tt := tt+a[h[i]];

if M > N then exit;

for i := M+1 to MN do

if h[i] > 0 then begin

Trang 9

if id[i] > 0 then begin

Doc; InitID; IDQuickSort(1,n);

XepViec; DonViec; XepTiep; GhiTep;

const string fn = "Viec.inp";

const string gn = "Viec.out";

static public Viec [] v; // cac viec

static public int n = 0; // so luong viec static public int tong = 0;

static public int[] h;

static public int k = 0;

static void Main()

Trang 10

int tmax = 0;

for (int i = 0; i < n; ++i)

if (v[i].t > tmax) tmax = v[i].t;

int tt = tmax + n + 1;

h = new int[tt];

// Khoi tri cho h

for (int i = 0; i < tt; ++i) h[i] = 0; tong = 0;

for (int i = 0; i < n; ++i)

// Sap cac viec giam theo tien thuong

static void QSort(int d, int c)

Trang 11

if (i <= j)

{

t = v[i]; v[i] = v[j]; v[j] = t; ++i; j;

// Doc lai file gn de kiem tra ket qua

static void Test() tự viết

static void Doc()

{

int [] a = Array.ConvertAll(

(File.ReadAllText(fn)).Split(

new char[] { '\n', ' ', '\t', '\0', '\r' }, StringSplitOptions.RemoveEmptyEntries), new Converter<string, int>(int.Parse));

n = a[0];

v = new Viec[n];

Console.WriteLine(" n = " + n);

int k = 1;

for (int i = 0; i < n; ++i)

v[i] = new Viec(a[k++],a[k++],i+1); }

public struct Viec

{

public int t; // Thoi han giao nop

public int thuong; // Tien thuong

public int id; // Ma so

public Viec(int th, int thg, int nn) { t = th; thuong = thg; id = nn; }

Dữ liệu vào: Tệp văn bản balo.inp:

- Dòng đầu tiên: hai giá trị nguyên dương N và M

- N dòng tiếp theo, mỗi dòng chứa hai giá trị nguyên dương d v cho mỗi vật,

trong đó d là trọng lượng, v là giá trị tính theo một đơn vị trọng lượng của

vật đó (đơn giá) Các số cách nhau qua dấu cách

Trang 12

3 8

16 6

- Vật thứ ba có trọng lượng 4, đơn giá 2,

- Vật thứ tư có trọng lượng 3, đơn giá 8,

- Vật thứ năm có trọng lượng 16, đơn giá 6

(tr - triệu đồng)

16

172

Dữ liệu ra: Tệp văn bản tên balo.out:

- N dòng, dòng thứ i cho biết trọng lượng cần lấy ở vật thứ i

- Dòng cuối cùng ghi tổng giá trị thu được

Hướng dẫn

Có nhiều bài toán thuộc họ xếp ba lô, thuật toán cho bài này thuộc lớp tham lam

Dễ thấy tiêu chuẩn chọn là giá đơn vị cao Ta duyệt các vật theo giá đơn vị từ cao trở xuống Vật được chọn sẽ được lấy tối đa Như vậy, nếu tổng trọng lượng các vật bằng hoặc lớn hơn sức mang của ba lô thì bao giờ ba lô cũng được xếp đủ

{t: tong trong luong con duoc xep vao balo}

{tt: tong gia tri da lay}

Trang 13

while gdv[id[j]] < x do dec(j);

tt := 0; {tong gia tri }

t := m; {trong luong con lai cua balo }

for i :=1 to n do

if t >= a[id[i]] then begin { lay tron vat id[i] }

t := t-a[id[i]];

tt := tt + (a[id[i]]*gdv[id[i]]);

end else { lay cho day balo } begin

tt := tt+(t*gdv[id[i]]); {lay vua du } a[id[i]] := t; {chinh lai vat cuoi }

Trang 14

const string fn = "BaLo.inp";

const string gn = "BaLo.out";

static public Item[] Items;

static public int[] t;

static public int n = 0; // so luong vat

static public int m = 0; // suc chua cua Ba lo static public int vh = 0; // Gia tri cua balo static void Main()

// Sap cac BaLo giam theo tien thuong

static public void QSort(int d, int c)

{

int i = d, j = c;

int m = Items[(d + c) / 2].Price;

Item t = new Item(0,0,0);

Trang 15

// Doc lai file gn de kiem tra ket qua

static public void Test() tự viết

Items = new Item[n];

for (int k = 2, i = 0; i < n; ++i, k+=2)

Items[i] = new Item(b[k], b[k+1], i); }

public struct Item // mo ta mot mat hang

{

public int Weight; // trong luong

public int Price; // don gia

public int Id; // ma so

public Item(int w, int p, int i)

{ Weight = w; Price = p; Id = i; }

}

} // BaLo

} // SangTao1

Bài 5.4 Cây bao trùm ngắn nhất

Cho một đồ thị liên thông G vô hướng bao gồm n đỉnh, mã số từ 1 đến n, và m

cạnh nối hai đỉnh với nhau Mỗi cạnh có chiều dài cho trước Tính liên thông của

đồ thị cho biết với hai đỉnh cho trước tuỳ ý ta luôn tìm được các cạnh gối đầu

nhau để đi từ đỉnh này đến đỉnh kia Hãy chỉ ra một phần P của đồ thị thoả các

tính chất sau:

Trang 16

(i) P chứa tất cả các đỉnh của G;

(ii) P chứa một số ít nhất các cạnh của G;

(iii) P là đồ thị liên thông;

(iv) Tổng chiều dài các cạnh của P là ngắn nhất

Đồ thị P thoả ba tính chất (i), (ii) và (iii) được gọi là cây bao trùm của đồ thị G Nếu P thoả thêm tính chất (iv) thì P được gọi là cây bao trùm ngắn nhất của G Một số tài liệu dùng thuật ngữ cây khung thay cho cây bao trùm và cây khung cực tiểu thay cho

cây bao trùm ngắn nhất

Bài toán trên có nhiều ứng dụng thực tiễn Một trong số ứng dụng đó được mô tả thông qua thí dụ sau:

Có n máy tính được nối với nhau thành mạng bằng cáp quang là một loại dây

truyền tin đắt tiền Trong mạng này, hai máy tính bất kì đều có thể liên lạc được với nhau trực tiếp hoặc thông qua một vài máy trung gian Ta gọi tính chất này là tính liên thông của mạng máy tính Hãy bỏ bớt một số dây nối để n máy tính trên vẫn liên thông được với nhau Mạng tối thiểu thu được chính là một cây bao trùm ngắn nhất của mạng ban đầu

Dữ liệu vào: tệp văn bản tên DOTHI.INP

- Dòng đầu tiên ghi hai số tự nhiên n và m cách nhau qua dấu cách, biểu thị

là (chiều dài mỗi cạnh được ghi sau dấu hai chấm):

cạnh 1 (1, 5): 1 cạnh 2 (4, 8): 1 cạnh 3 (7, 8): 1 cạnh 4 (2, 3): 2 cạnh 5 (1, 6): 2 cạnh 6 (3, 8): 3 cạnh 7 (1, 3): 4 Tổng chiều dài 7 cạnh đã chọn là: 14

Trang 17

Lưu ý rằng đồ thị kết quả thu được ở các bước trung gian có thể không liên thông

mà bao gồm nhiều mảnh liên thông (cây con) Loại đồ thị này được gọi là rừng Kết quả

cuối cùng sẽ là cây vì nó liên thông và được tạo thành từ n - 1 cạnh Ta vận dụng tổ

chức find-union cho các tập đỉnh rời nhau để quản lí các tập đỉnh được chọn nhằm phát

hiện chu trình Cạnh (x, y) khi được ghép vào đồ thị trung gian sẽ tạo thành chu trình khi và chỉ khi các đỉnh x và y cùng nằm trong một cây của đồ thị (rừng) trung gian đó

Như vậy mỗi cây con của đồ thị trung gian được quản lí như một tập con của tập các

đỉnh 1 n của đồ thị ban đầu Tập con này có phần tử đại diện chính là gốc của cây

tương ứng Phần tử này được chọn theo mã số nhỏ nhất Các đỉnh còn lại của cây con đều trỏ đến gốc đó

Dễ thấy cây bao trùm luôn luôn có n đỉnh và n - 1 cạnh

(* Pascal *)

(* -

DOTHI.PAS Cay bao trum ngan nhat

(thuat giai Kruskal)

var

a: array[0 MN] of CANH; { Mang cac canh }

d: array[1 MN] of integer;{dung cho find-union } n: integer; {n: so dinh }

m: integer; {so canh }

(* Sap canh tang theo len *)

procedure qsort(d,c: integer);

Trang 18

begin while a[i].len < m do i := i+1;

{Tim dai dien cua tap chua x }

function Find(x: integer): integer;

function Union(x,y: integer): Boolean;

Trang 19

const string fn = "DoThi.inp";

const string gn = "DoThi.out";

// do thi co n dinh

// m canh (u,v)

// u la dinh dau, v - dinh cuoi

// Len - chieu dai canh

static int[] d ; // to chuc Find-Union

static int n = 0; // so dinh cua do thi

static int m = 0; // so canh cua do thi

static Canh[] cc; // Tap cac canh

static int [] t; // canh duoc chon

static int k; // so canh duoc chon

static int sum = 0;

static void Main()

// Khoi tri cho Find-Union

for (int i = 1; i <= n; ++i) d[i] = i; for (int i = 0; i < m; ++i)

if (Union(cc[i].U,cc[i].V))

{ t[k++] = i; sum += cc[i].Len; } }

static void Ghi()

{

Ngày đăng: 03/10/2013, 02:20

HÌNH ẢNH LIÊN QUAN

Đồ thị cho biết với hai đỉnh cho trước tuỳ ý ta luôn tìm được các cạnh gối đầu - PHƯƠNG PHÁP THAM LAM
th ị cho biết với hai đỉnh cho trước tuỳ ý ta luôn tìm được các cạnh gối đầu (Trang 15)
Đồ thị P thoả ba tính chất (i), (ii) và (iii) được gọi là  cây bao trùm của đồ thị G. - PHƯƠNG PHÁP THAM LAM
th ị P thoả ba tính chất (i), (ii) và (iii) được gọi là cây bao trùm của đồ thị G (Trang 16)

TỪ KHÓA LIÊN QUAN

w