Đề tài:- Bài toán người đưa thư-Xây dựng chương trình giải quyết bài toán người đưa thư theo giải thuật gense với phương pháp chọn ElitismI/Bài toán người đưa thư:Bài toán người đưa thư(hay còn gọi là bài toán người du lịch-TSP) là một bài toán về ý niệm rất đơn giản song lại khá kinh điển.Một người đưa thư phải ghé mỗi thành phố trong vùng của anh ta,chính xác một lần rồi trở về điểm khởi hành.Chi phí đi lại giữa từng cặp thành phố được cho trước,anh ta phải lập kế hoạch cho hành trình của mình ra sao để tổng chi phí cho toàn hành trình là tối thiểu.Không gian tìm kiếm của TSP là tập các hoán vị của n thành phố.Bất cứ hoán vị nào của n thành phố này cũng là một lời giải chấp nhận được (là toàn bộ một hành trình qua các thành phố).Lời giải tối ưu là một hoán vị với chi phí tối thiểu của hành trình.Kích thước của không gian tìm kiếm là n! II/Giải thuật genesThuật toán gense mô phỏng tiến hóa tự nhiên ở mức gen sử dụng tư tưởng của chọn lọc tự nhiên.Thuật giải di truyền hình thành dựa trên quan niệm cho rằng quá trình tiến hóa tự nhiên là quá trình hoàn hảo nhất,hợp lí nhất và tự nó đã mang tính tối ưu.Quá trình tiến hóa thể hiện tính tối ưu ở chỗ thế hệ sau bao giờ cũng tốt hơn thế hệ trước.Tiến hóa tự nhiên được duy trì bởi 2 quá trình cơ bản:sinh sản và chọn lọc tự nhiên.Cá thể nào phát triển hơn,thích ứng hơn với môi trường sẽ bị đào thải.Một cá thể mô tả một lời giả ứng viên cho bài toán.Một cá thể “alive”,gọi là quần thể được tiến hóa từ thế hệ này đến thế hệ khác phụ thuộc vào sự thích nghi của cá thể.Thế hệ sinh ra sẽ chứa lời giải của bài toán.Ban đầu sinh ra thế hệ khởi tạo quần thể P(0),chỉ số i chỉ ra thế hệ thứ i.Lặp cho đến khi quần thể hội tụ hoặc tiêu chuẩn kết thúc đạt được.Sau đó đánh giá độ thích nghi của mỗi cá thể trong P(i).Lựa chọn các cha từ P(i) dựa trên độ thích nghi của chúng trong P(i).Áp dụng các toán tử gen(lai ghép và đột biến) từ các cha đã chọn để sinh ra các con.Đạt được thế hệ tiếp theo P(i+1) từ các con và các cá thể ở thế hệ P(i).Các thành phần cơ bản của thuật toán gen:-Mã hóa -Khởi tạo quần thể-Hàm thích nghi-Lựa chọn cho sự kết hợp lại-Lai ghép-Đột biến-Chiến lược thay thế-Tiêu chuẩn kết thúcÁp dụng vào bài toán người đưa thư:-Mã hóa: Sử dụng mã hóa dạng hoán vị.Tất cả các nhiễm sắc thể là chuỗi các số biểu diễn vị trí của các thành phố trong một dãyVí dụ: NST A 1 5 3 2 6 4 7 9 8 NST B 8 5 6 7 2 3 1 4 9-Khởi tạo quần thể: Ta chọn ngẫu nhiên một số cá thể tạo thành một quần thể. -Hàm thích nghi:để tìm ra cá thể tốt hay xấu.Đối với bài toán người đưa thư hàm thích nghi chính là tổng chi phí mà
Trang 1Đề tài:
- Bài toán người đưa thư
-Xây dựng chương trình giải quyết bài toán theo giải thuật gense với phương pháp chọn Elitism
I/Bài toán người đưa thư:
Bài toán người đưa thư(hay còn gọi là bài toán người du lịch-TSP) là một bài toán về ý niệm rất đơn giản song lại khá kinh điển.Một người đưa thư phải ghé mỗi thành phố trong vùng của anh ta,chính xác một lần rồi trở về điểm khởi hành.Chi phí đi lại giữa từng cặp thành phố được cho trước,anh ta phải lập kế hoạch cho hành trình của mình ra sao để tổng chi phí cho toàn hành trình là tối thiểu.Không gian tìm kiếm của TSP là tập các hoán vị của n thành phố.Bất cứ hoán vị nào của n thành phố này cũng là một lời giải chấp nhận được (là toàn bộ một hành trình qua các thành phố).Lời giải tối ưu là một hoán vị với chi phí tối thiểu của hành trình.Kích thước của không gian tìm kiếm là n!
II/Giải thuật genes
Thuật toán gense mô phỏng tiến hóa tự nhiên ở mức gen sử dụng tư tưởng của chọn lọc tự nhiên.Thuật giải di truyền hình thành dựa trên quan niệm cho rằng quá trình tiến hóa tự nhiên là quá trình hoàn hảo nhất,hợp lí nhất và
tự nó đã mang tính tối ưu.Quá trình tiến hóa thể hiện tính tối ưu ở chỗ thế hệ sau bao giờ cũng tốt hơn thế hệ trước.Tiến hóa tự nhiên được duy trì bởi 2 quá trình cơ bản:sinh sản và chọn lọc tự nhiên.Cá thể nào phát triển
hơn,thích ứng hơn với môi trường sẽ bị đào thải.Một cá thể mô tả một lời giả ứng viên cho bài toán.Một cá thể “alive”,gọi là quần thể được tiến hóa từ thế
hệ này đến thế hệ khác phụ thuộc vào sự thích nghi của cá thể.Thế hệ sinh ra
sẽ chứa lời giải của bài toán.Ban đầu sinh ra thế hệ khởi tạo quần thể
P(0),chỉ số i chỉ ra thế hệ thứ i.Lặp cho đến khi quần thể hội tụ hoặc tiêu chuẩn kết thúc đạt được.Sau đó đánh giá độ thích nghi của mỗi cá thể trong P(i).Lựa chọn các cha từ P(i) dựa trên độ thích nghi của chúng trong P(i).Áp
Trang 2dụng các toán tử gen(lai ghép và đột biến) từ các cha đã chọn để sinh ra các con.Đạt được thế hệ tiếp theo P(i+1) từ các con và các cá thể ở thế hệ P(i).
Các thành phần cơ bản của thuật toán gen:
- Mã hóa
- Khởi tạo quần thể
- Hàm thích nghi
- Lựa chọn cho sự kết hợp lại
- Lai ghép
- Đột biến
- Chiến lược thay thế
- Tiêu chuẩn kết thúc
Áp dụng vào bài toán người đưa thư:
- Mã hóa: Sử dụng mã hóa dạng hoán vị.Tất cả các nhiễm sắc thể là chuỗi các số biểu diễn vị trí của các thành phố trong một dãy
Ví dụ: NST A 1 5 3 2 6 4 7 9 8
NST B 8 5 6 7 2 3 1 4 9
- Khởi tạo quần thể: Ta chọn ngẫu nhiên một số cá thể tạo thành một quần thể
- Hàm thích nghi:để tìm ra cá thể tốt hay xấu.Đối với bài toán người đưa thư hàm thích nghi chính là tổng chi phí mà người đó đi hết tất cả các thành phố.
- Lựa chọn cho sự kết hợp lại:Sử dụng phương pháp chọn Elitism
Phương pháp Elitism cho phép copy những cá thể tốt (hoặc một vài cá
thể tốt) sang quần thể mới
Thành phần còn lại của quần thể được tạo từ cách khác.
Phương pháp Elitism có thể tăng tốc cho GA, vì nó ngăn không làm
mất cá thể tốt.
Trang 3- Lai ghép+ đột biến: Single point crossover
Lựa chọn một điểm để lai ghép, permutation được sao chép từ điểm đầu tiên đến điểm lai ghép, sau đó cha còn lại được duyệt qua từng số
và nếu số đó chưa có trong con, nó được thêm theo thứ tự của NST thứ hai
(1 2 3 4 5 | 6 7 8 9) + (4 5 3 6 2 9 1 7 8) = (1 2 3 4 5 6 9 7 8)
III/Chương trình 1-Form main:
Khi nhấn chuột vào nút nhập thì goi được form nhập
Khi nhấn chuột vào nút giải thì gọi được form giải
public partial class Form_main: Form
{
public Form_main()
{
InitializeComponent();
}
private void nhậpToolStripMenuItem_Click(object sender,
EventArgs e)
{
foreach (Form frm in this.MdiChildren)
Trang 4{
frm.Close();
}
Form_nhap fe = new Form_nhap();
fe.MdiParent = this;
fe.Show();
nhap.Enabled = false;
giai.Enabled = true;
}
private void giảiToolStripMenuItem_Click(object sender,
EventArgs e)
{
foreach (Form frm in this.MdiChildren)
{
frm.Close();
}
Form_giai fr = new Form_giai();
fr.MdiParent = this;
fr.Show();
nhap.Enabled = true;
giai.Enabled = false;
}
private void Form_main_Load(object sender, EventArgs e) {
}
}
}
2-Form nhập
Trang 5Trên form nhập ta dùng chuột để chọn vị trí các nhà(thành phố).Sau đó điền giá trị thể hiện chi phí giữa các thành phố vào các ô textbox rồi nhấn vào nút thêm giá để lưu các giá trị vào file: dt1.text để lưu tọa độ của các nhà (thành phố) và dt2.text để lưu giá trị chi phí giữa các nhà.
public partial class Form_nhap: Form
{
dothi dt;
TextBox[,] tb;
Point[] diem;
public Form_nhap()
{
InitializeComponent();
}
// Hàm lưu tọa độ của nhà
private void luunha(int x, int y)
{
StreamReader sr = new StreamReader("dt1.txt");
string sonutcu = sr.ReadLine();
int sonutmoi = Convert.ToInt32(sonutcu) + 1;
string temp = sr.ReadToEnd();
sr.Close();
StreamWriter sw = new StreamWriter("dt1.txt");
sw.WriteLine(sonutmoi);
sw.WriteLine(temp);
string toado = x.ToString() + "," + y.ToString();
sw.Write(toado);
sw.Close();
}
//Hàm xóa dữ liệu trên file dt1.text và dt2.text
private void xoadulieu()
{
StreamWriter sw1 = new StreamWriter("dt1.txt");
sw1.Write("");
sw1.Close();
StreamWriter sw2 = new StreamWriter("dt2.txt");
sw2.Write("");
sw2.Close();
}
private void xoahienthi()
{
foreach (TextBox tbs in this.tb)
{
this.Controls.Remove(tbs);
}
foreach (nha n in dt.Nha)
{
this.Controls.Remove(n);
}
}
private void hienthi()
Trang 6{
// Hiển thị nhà:
dt = new dothi("dt1.txt");
for (int i = 0; i < dt.Sonha; i++)
{
this.Controls.Add(dt.Nha[i]);
}
//Hiên thị giá đường dưới dạng textbox
diem = new Point[dt.Sonha];
for (int i = 0; i < dt.Sonha; i++)
{
diem[i] = new Point(dt.Nha[i].Location.X +
dt.Nha[i].Height / 2, dt.Nha[i].Location.Y + dt.Nha[i].Width / 2); }
tb = new TextBox[dt.Sonha, dt.Sonha];
for (int i = 0; i < dt.Sonha; i++)
{
for (int j = 0; j < dt.Sonha; j++)
{
tb[i, j] = new TextBox();
tb[i, j].Text = "0";
}
}
for (int i = 0; i < dt.Sonha; i++)
{
for (int j = i + 1; j < dt.Sonha; j++)
{
tb[i, j].Size = new Size(23, 18);
tb[i, j].Text = dt.Mangcost[i, j].ToString(); tb[i, j].Location = new Point((diem[i].X + diem[j].X) / 2, (diem[i].Y + diem[j].Y) / 2);
this.Controls.Add(tb[i, j]);
}
}
}
private void luugia()
{
for (int i = 0; i < dt.Sonha; i++)
{
for (int j = i+1; j < dt.Sonha; j++)
{
tb[j, i].Text = tb[i, j].Text;
}
}
StreamWriter sw = new StreamWriter("dt2.txt");
string temp = null;
for (int i = 0; i < dt.Sonha; i++)
{
for (int j = 0; j < dt.Sonha; j++)
{
temp = temp + tb[i, j].Text + " | ";
}
Trang 7temp = temp + "\r\n";
}
sw.WriteLine(temp);
sw.Close();
}
private void luugiasauthemnha()
{
string temp = null;
if (dt.Sonha == 0)
{
StreamWriter sw = new StreamWriter("dt2.txt"); temp = "00 |";
sw.WriteLine(temp);
sw.Close();
}
else
{
StreamReader sr = new StreamReader("dt2.txt"); string[] dauvao = new string[dt.Sonha - 1]; for (int i = 0; i < dt.Sonha - 1; i++)
{
dauvao[i] = sr.ReadLine();
}
sr.Close();
StreamWriter sw = new StreamWriter("dt2.txt"); for (int i = 0; i < dt.Sonha - 1; i++)
{
temp = temp + dauvao[i] + " | 00 |";
temp = temp + "\r\n";
}
for (int i = 0; i < dt.Sonha; i++)
{ temp = temp + "00 | "; }
sw.WriteLine(temp);
sw.Close();
}
}
private void themtb()
{
tb = new TextBox[dt.Sonha, dt.Sonha];
for (int i = 0; i < dt.Sonha; i++)
{
for (int j = 0; j < dt.Sonha; j++)
{
tb[i, j] = new TextBox();
tb[i, j].Text = "0";
}
}
for (int i = 0; i < dt.Sonha; i++)
{
for (int j = i + 1; j < dt.Sonha; j++)
{
Trang 8tb[i, j].Size = new Size(23, 18);
tb[i, j].Text = dt.Mangcost[i, j].ToString(); tb[i, j].Location = new Point((diem[i].X +
diem[j].X) / 2, (diem[i].Y + diem[j].Y) / 2);
this.Controls.Add(tb[i, j]);
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
hienthi();
}
private void Form1_Paint(object sender, PaintEventArgs e) {
Graphics dohoa = this.CreateGraphics();
Pen to = new Pen(Color.Red, 2);
for (int i = 0; i < dt.Sonha; i++)
{
for (int j = i + 1; j < dt.Sonha; j++)
{
dohoa.DrawLine(to,diem[i],diem[j]);
}
}
}
private void button1_Click(object sender, EventArgs e)
{
luugia();
}
private void Form1_MouseDown(object sender, MouseEventArgs e) {
if (checkBox1.Checked)
{
xoahienthi();
luunha(e.X, e.Y);
dt = new dothi("dt1.txt");
hienthi();
this.Refresh();
}
}
private void button2_Click(object sender, EventArgs e)
{
xoahienthi();
xoadulieu();
dt = new dothi();
checkBox1.Checked = true;
hienthi();
this.Refresh();
}
}
}
Trang 93-Form giải:
Sau khi đã kích chuột vào nút thêm giá trên form nhập.Kích vào “giải” trên form 2 thì xuất hiên form giải.Trên form giải ta kích chuột vào nút “giải” thì
sẽ được kết quả của bài toán.
public partial class Form_giai: Form
{
public Form_giai()
{
InitializeComponent();
}
dothi dt;
TextBox[,] tb;
Point[] diem;
private void hienthi()
{
// Hiển thị nhà:
dt = new dothi("dt1.txt","dt2.txt");
Trang 10for (int i = 0; i < dt.Sonha; i++)
{
this.Controls.Add(dt.Nha[i]);
}
//Hiên thị giá đường dưới dạng textbox
diem = new Point[dt.Sonha];
for (int i = 0; i < dt.Sonha; i++)
{
diem[i] = new Point(dt.Nha[i].Location.X +
dt.Nha[i].Height / 2, dt.Nha[i].Location.Y + dt.Nha[i].Width / 2); }
tb = new TextBox[dt.Sonha, dt.Sonha];
for (int i = 0; i < dt.Sonha; i++)
{
for (int j = 0; j < dt.Sonha; j++)
{
tb[i, j] = new TextBox();
tb[i, j].Text = "0";
}
}
for (int i = 0; i < dt.Sonha; i++)
{
for (int j = i + 1; j < dt.Sonha; j++)
{
tb[i, j].Size = new Size(23, 18);
tb[i, j].Text = dt.Mangcost[i, j].ToString(); tb[i, j].Location = new Point((diem[i].X + diem[j].X) / 2, (diem[i].Y + diem[j].Y) / 2);
this.Controls.Add(tb[i, j]);
}
}
}
private void button1_Click(object sender, EventArgs e) {
dothi dt = new dothi("dt1.txt", "dt2.txt");
gene ge = new gene(dt, 10, 5, 100);
ge.tinhtoan();
Graphics dohoa = this.CreateGraphics();
Pen to = new Pen(Color.Blue, 4);
for (int i = 0; i < dt.Sonha-1; i++)
{
dohoa.DrawLine(to, diem[ge.KQ[i]],
diem[ge.KQ[i+1]]);
}
string temp = "Quần thể lai:"+ "\n";
string temp2 = "Quần thể đầu:"+ "\n";
string temp3 = "Cá thể chọn từ quần thể"+ "\n";
for (int j = 0; j < ge.laiquanthe().GetLength(0); j++) {
for (int i = 0; i < ge.DT.Sonha; i++)
Trang 11{
temp = temp + ge.laiquanthe()[j, i].ToString(); }
temp = temp + " " + ge.tinhtoangiatri(ge.laiquanthe(), j).ToString() + "\n";
}
for (int j = 0; j < ge.hoanvi.GetLength(0); j++)
{
for (int i = 0; i < ge.DT.Sonha; i++)
{
temp2 = temp2 + ge.hoanvi[j, i].ToString();
}
temp2 = temp2 + " " + ge.tinhtoangiatri(ge.hoanvi, j).ToString() + "\n";
}
for (int j = 0; j < ge.qttot.GetLength(0); j++)
{
for (int i = 0; i < ge.DT.Sonha; i++)
{
temp3 = temp3 + ge.qttot[j, i].ToString();
}
temp3 = temp3 + " " + ge.tinhtoangiatri(ge.qttot, j).ToString() + "\n";
}
string temp5 = "Quần thể lai tốt:" +"\n";
for (int j = 0; j < ge.qtlai.GetLength(0); j++)
{
for (int i = 0; i < ge.DT.Sonha; i++)
{
temp5 = temp5 + ge.qtlai[j, i].ToString();
}
temp5 = temp5 + " " + ge.tinhtoangiatri(ge.qtlai, j).ToString() + "\n";
}
string temp6 = "Cộng quần thể:" + "\n";
for (int j = 0; j < ge.congquanthe().GetLength(0); j++) {
for (int i = 0; i < ge.DT.Sonha; i++)
{
temp6 = temp6 + ge.congquanthe()[j, i].ToString(); }
temp6 = temp6 + " " +
ge.tinhtoangiatri(ge.congquanthe(), j).ToString() + "\n";
}
label2.Text = temp;
label4.Text = temp3;
label3.Text = temp2;
label5.Text = temp5;
label6.Text = temp6;
}
private void button1_Paint(object sender, PaintEventArgs e) {
Graphics dohoa1 = this.CreateGraphics();
Pen to = new Pen(Color.Red, 2);
for (int i = 0; i < dt.Sonha; i++)
Trang 12{
for (int j = i + 1; j < dt.Sonha; j++)
{
dohoa1.DrawLine(to, diem[i], diem[j]);
}
}
}
private void Gense(object sender, EventArgs e)
{
dothi dt = new dothi("dt1.txt", "dt2.txt");
hienthi();
}
}
}
Label “Quần thể đầu” hiển thị kết quả quần thể ban đầu khi ta chọn ngẫu nhiên các hoán vị
Label “Cá thể chọn từ quần thể” hiển thị kết quả các cá thể tốt nhất được chọn từ quần thể ban đầu
Label “Quần thể lai” thể hiện kết quả các cá thể được lai từ các cá thể tốt nhất đã được chọn.
Label “Quần thể lai tốt” thể hiện kết quả các cá thể tốt nhất trong quần thể lai
Label “Cộng quần thể ” thể hiện quần thể cuối cùng gồm các cá thể ở quần thể “Các cá thể chọn từ quần thể” được copy sang và các cá thể ở “Quần thể lai tốt” được sắp xếp theo thứ tự tăng dần cảu giá trị chi phí đường đi.
Đáp số bài toán là kết quả trên cùng của “Cộng quần thể”.
Class thuật toán: Gene class
class gene
{
private dothi _dt;
private int[] _ketqua;
private int sohoanvi;
public int[,] hoanvi;
public int[,] qttot;
public int[,] qtlai;
public int sotot;
public int solai;
private int solanlap;
public dothi DT
{
get { return _dt; }
set { _dt = value; }