Bài giảng Toàn tối ưu backtracking rất dễ hiểu
Trang 1Tìm phương án tối ưu
Backtracking nhánh cận
Trang 2Bài 1
Trang 3x1 x2 x3 x4 X C A <b FOPT = max
0 0 0 0 0000 0 0 0 Chọn
1 0001 1 1 1 Chọn lại
1 0 0010 3 2 3 Chọn lại
1 0011 4 3 4 Chọn lại
1 0 0 0100 5 3 5 Chọn lại
1 0101 6 4 6 Chọn lại
1 0 0110 8 5 8 Chọn lại
1 0111 9 6 9 Chọn lại
1 0 0 0 1000 8 4 _ Không
1 1001 9 5 _ Không
1 0 1010 11 6 11 Chọn lại
1 1011 12 7 12 Chọn lại
1 0 0 1100 13 7 13 Chọn lại
1 1101 14 8 14 Chọn lại
1 0 1110 16 9 _ Không thỏa
1 1111 17 10 _ Không thỏa
n= 4, b = 8
Ví dụ minh họa Liệt kê nhị phận
Trang 4Tập biến X= (x1 x2 x3 xn), số biến = n
Tập miền trị D =(D1 D2 D3 Dn)
void Try ( int i, X , n)
{ j Di ∀ ∈
{ if ( acceptable(xi, j))
{ xi = j;
if (i==n) Process (CấuHìnhCủa X) else Try (i+1, X, n)
}
}
Trang 5Backtracking: Phương án tối ưu
#define MAX 100 //so vat toi da
int n;//so vat thuc su
int B;//suc chua cai tui
int A[MAX];// mang chua trong luong cua cac
vat: a1, ,an
int C[MAX];//mang chua gia tri cua cac
vat: c1, ,cn
//mot phuong an la mot day nhi phan
x1, ,xn (xi=0/1)
int X[MAX];//mang chua phuong an hien
tai
//phuong an toi uu la phuong an cho gia
tri lon nhat
int XOPT[MAX];//mang chua phuong an
toi uu: xopt[i]=0/1
//gia tri toi uu la gia tri su dung ung voi
phuong an toi uu
int FOPT;//mang chua gia tri toi uu
void Try(int i)//lan luot xet tat ca cac phuong an {
for(int j=0;j<=1;j++) { X[i]=j;S=S+A[i]*X[i];P=P+C[i]*X[i];
if(i==n) { if ( S<=B && FOPT < P) { FOPT = P; //Cap nhat gia tri toi uu for(int k=1; k<=n; k++) // Cap nhat PATU XOPT[k] = X[k];
} } else if(S<B) Try(i+1);
S=S-A[i]*X[i];P=P-C[i]*X[i];
} }
Trang 6Bài 2
Một cán bộ quản lý N nhân viên, mỗi ngày cần thực hiện
N việc đồng thời Biết mỗi nhân viên đều có thể thực
hiện được tất cả N công việc nhưng với thời gian khác nhau Thời gian để nhân viên thứ i thực hiện công việc j
là Ci,j (1 ≤ i, j ≤ N ≤ 100) Hãy viết chương trình tìm cách
bố trí N việc cho N nhân viên sao cho tổng thời gian thực
hiện trong ngày là ít nhất
3
47
Trang 7Hoán vị các công việc
j = 123
B[j]= 111
NVi= 1 2 3=n cv FOPT
CVi 29 16 15 123 60 Chọn
11 12 132 52 Chọn lại
21 28 15 213 64 Không
11 15 231 47 chọn lại
46 28 12 312 86 không
16 15 321 77 không
111 011 001 000
011 010
101 001
101 100
110 010
110 100
Thoi gian 47
NV 1 2 3
CV 2 3 1
Trang 8Viết chương trình hoán vị bằng backtracking
void Init (int *B, int n)
{ for (int i=1; i<=n; i++) B[i]=TRUE;
}
void Process (int result[], int n, int count)
{ printf(‘’\n Hoan vi thu %d: \t ’’,count);
for (int i=1; i<=n; i++) printf(‘’%d,’’, result[i]);
}
Lời gọi hàm: Init(B,n); Try(1,count)
với count = 0
void Try ( int i, int &count) { for (int j=1; j <= n; j++ )
if (B[j]) { result[i]=j;
B[j]=FALSE;
if (i==n) { count++;
Process (result, n, count); }
else Try (i+1, count);
B[j]=TRUE;
}
}
Trang 9Viết chương trình sắp xếp công việc bằng
thuật toán backtracking
void Init (int *B, int n)
{ for (int i=1; i<=n; i++) B[i]=TRUE;
}
Lời gọi hàm: Init(B,n); Try(1)
void Try ( int i) { for (int j=1; j <= n; j++ )
if (B[j]) { X[i]=j;
P = P +A[i][j];
B[j]=FALSE;
if (i==n) {if ( FOPT > P) { FOPT = P; //Cap nhat gia tri toi uu for(int k=1; k<=n; k++) // Cap nhat PATU XOPT[k] = X[k];
} } else Try (i+1);
B[j]=TRUE;
P = P -A[i][j];
}
}
Trang 10Bài tập
Hãy viết chương trình liệt kê tất cả các số tự nhiên K thỏa mãn đồng thời các điều kiện (a), (b), (c) và (d) dưới đây, biết rằng P, S, B được nhập từ bàn phím:
a) K là số nguyên tố có từ a đến b chữ số (a,b nhập từ bàn phím và 1<=a,b<=9; a<=b)
b) Các chữ số của K khác P (P = 0, 1, 2, ,9).
c) Tổng các chữ số của K chia hết cho S.
d) Biểu diễn của K ở hệ cơ số B là một số thuận nghịch (số
K được gọi là thuận nghịch nếu ta đọc từ trái sang phải hay từ phải sang trái các chữ số của K ta đều nhận
được chính nó).
Trang 11Khai báo
const max=30;
int a=3,b=6;
int X[max];//chua so can tim: x1x2 xn (a<=n<=b) int S,P,B;
int count=0;
long K=0;
Trang 12Tinh giá trị K của dãy chữ số X
void tinhK(int i)//tinh K co i chu so X1X2 Xi { long q=1;K=0;
for(int j=1;j>=i;j++)
{
K=K*10+X[j];
}
}
Trang 13Gọi đệ qui
void Try(int i)
{ for(int j=0;j<=9;j++)
{ if((i!=1&&j!=P)||(i==1&&j!=0&&j!=P))
X[i]=j;
if(i>=a&&i<=b) { tinhK(i);
if(ktnt()==1&&kttong(i)==1&&kttn(i)==1)
printf("\n%d)%ld",++count,K);
} if(i<b) Try(i+1);
} }
}
Trang 14Hàm kiểm tra
int ktnt()//kiem tra K co la nguyen to kg?
{ int nt=1;
for(long i=2;i<=sqrt(K);i++) if(K%i==0) {nt=0;break;}
return nt;
}
//kiem tra xem K=x1 xi co tong x1+ +xi co chia het cho S hay kg? int kttong(int i)
{ long M=0;//M la tong cac chu so cua K
for(int j=1;j<=i;j++) M=M+X[j];
if (M%S==0) return 1;
else return 0;
}
Trang 15Hàm kiểm tra
//kiem tra K bieu dien o co so B co la so thuan nghich hay kg? int kttn()
{ int d[max];//dm d1 la bieu dien o co so B cua K long T=K; int m=0;
do {d[++m]=T%B;T=T/B;
}while(T!=0);
int tn=1;
for(int i=1;i<=m/2;i++) if(d[i]!=d[m-i+1]) {tn=0;break;}
return tn;
}