THUẬT TOÁN QUY HOẠCH ĐỘNG(điền bảng phương án)
Gồm Có (Bài toán tam giác số , Bài toán hái táo, Bài toán cái túi,Bài toán giao hàng (du
lịch),Dãy Fibonaci , Giai thừa, Phân tích số,Dãy con tăng dài nhất ,Sudoku)
1. Bài toán tam giác số :
int TamGiacQuyHoachDong(int a[MAX][MAX],int n,int path[MAX])
{
int b[MAX][MAX],maxT=0,vtkt,k=0;
b[0][0]=a[0][0];
for(int i=1;i<n;i++)
for(int j=0;j<=i;j++)
{
//quy hoạch
if(j==0 || j==i)//đường biên
if(j==0)
b[i][j]=a[i][j]+b[i-1][j];
else
b[i][j]=a[i][j]+b[i-1][j-1];
else//khoảng giữa
if(a[i-1][j-1]>a[i-1][j])
b[i][j]=a[i][j]+b[i-1][j-1];
else
b[i][j]=a[i][j]+b[i-1][j];
if(i==n-1)//tìm tổng đường đi lớn nhất
if(maxT==0)//khởi tạo
{
maxT=b[i][j];
vtkt=j;
}
else//so sánh
if(maxT<b[i][j])
{
maxT=b[i][j];
vtkt=j;
}
}
inMat(b,n);
//lưu vị trí
int i=n-2;
path[k++]=vtkt;
while(i!=0)
{
//truy vết
if(a[i][vtkt]>a[i][vtkt-1])
path[k++]=vtkt;
else
{
path[k++]=vtkt-1;
vtkt ;
}
i ;
}
path[k++]=0;
return maxT;
}
2. Bài toán hái táo :
//quy hoạch động
int HaiTaoQuyHoachDong(int a[MAX][MAX],int n,int path[MAX])
{
int b[MAX][MAX]={0},soTao=0,vtkt,k=n-1;
//hàng đầu tiên ko đổi
for(int i=0;i<n;i++)
b[i][0]=a[i][0];
//tính các hàng còn lại
for(int j=1;j<n;j++)//hàng dọc
for(int i=0;i<n;i++)//hàng ngang
{
int vtd=timCayNhieuTrai(b,n,i,j-2);//tìm vi trí cây nhiều
trái
b[i][j]=b[vtd][j-1]+a[i][j];//quy hoạch
if(j==n-1)
if(soTao==0){
soTao=b[i][j];
vtkt=i;
}
else{
if(soTao<b[i][j]){
soTao=b[i][j];
vtkt=i;
}
}
}
//ma trận kết quả
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
printf("%2d ",b[i][j]);
printf("\n");
}
//đường đi
int c=4;
path[k ]=vtkt;
while(c!=0)
{
int vtcay=timCayNhieuTrai(b,n,vtkt,c-2);
path[k ]=vtcay;
vtkt=vtcay;
c ;
}
return soTao;
}
int timCayNhieuTrai(int a[MAX][MAX],int n,int i,int j)
{
int maxcay=a[i][j+1],vtm=i;
if(a[i+1][j+1]>maxcay && i+1 <n)
{
maxcay=a[i+1][j+1];
vtm = i+1;
}
if(a[i-1][j+1]>maxcay && i-1>=0)
{
maxcay=a[i-1][j+1];
vtm = i-1;
}
return vtm;
}
3. Bài toán cái túi :
//Bài toán: Bài toán cái túi (mỗi loại 1 món đồ)
void giai(int W[], //mảng chứa tr.lượng các đồ vật
int V[], //mảng chứa giá trị các đồ vật
int n, //số loại đồ vật
int w, //sức chứa của cái túi
int K[][MAX]){ //mảng 2 chiều chứa kết quả
//điền toàn bộ dòng 0 của ma trận K bằng giá trị 0
for(int j=0; j<=w; j++) K[0][j] = 0;
int i,j;
for(i=1; i<=n; i++) //lần lượt xét từng đồ vật
for(j=0; j<=w; j++) //điền giá trị các ô trên dòng i
{
//gán bằng với giá trị trước khi xét món i
K[i][j] = K[i-1][j];
//Nếu chọn món i có lợi hơn
if (j>=W[i] && K[i][j]<K[i-1][j-W[i]]+V[i])
K[i][j] = K[i-1][j-W[i]]+V[i];
}
}
//Trả về giá trị lớn nhất có thể lấy được(chưa viết truy vết)
int giai2(int W[],
int V[],
int n,
int w,
int mark[]) //đánh dấu những món được chọn
{
int L1[MAX]; //dòng đầu của ma trận (làm cơ sở tính)
int L2[MAX]; //dòng thứ 2 cần tính toán
//tự code nhé
int tang=0;
for(int j=0; j<=w; j++) L1[j] = 0;
int i,j;
for(i=1; i<=n; i++) //lần lượt xét từng đồ vật
{
//chưa chọn món nào hết
for(int j=0; j<=w; j++) mark[j] = 0;
tang=0;
for(j=0; j<=w; j++) //điền giá trị vào mảng L2 dựa trên mảng L1
{
//gán bằng với giá trị trước khi xét món i
L2[j] = L1[j];
//Nếu chọn món i có lợi hơn
if (j>=W[i] && L2[j]<L1[j-W[i]]+V[i])
{
L2[j] = L1[j-W[i]]+V[i];
}
}
for(int ka=0;ka<=w;ka++)
{
L1[ka]=L2[ka];
printf("%3d",L1[ka]);
}
cout<<endl;
}
Void main()
{
giai(W,V,n,w,K);
for(int e=1;e<=n;e++)
{
cout<<e<<":";
for(int j=0;j<=w;j++)
printf("%3d",K[e][j]);
cout<<endl;
}
cout <<"Gia tri lon nhat voi w="<<w<<" la: " <<K[n][w];
cout <<"\nDanh sach cac mon duoc chon:\n";
//truy vết của void giai
int i=n, tmpw = w;
while (i!=0){
if (K[i][tmpw]!=K[i-1][tmpw]){
cout <<i <<" ";
tmpw -= W[i];
}
i ;
}
}
//Bài toán: Bài toán cái túi (số lượng món đồ ko giới hạn)
4. Bài toán giao hàng (du lịch) :
5. Dãy Fibonaci :
//Cách 1: sử dụng quy hoạch động
//Lưu trữ kết quả trong 1 mảng 1 chiều có n phần tử
//Độ phức tạp: O(n)
//VD, với n=8, mảng tmp: x 1 1 2 3 5 8 13 21
long F1(int n) {
long tmp[MAX];
tmp[1] = tmp[2] = 1; //không dùng ptử số 0
for(int i=3; i<=n; i++)
tmp[i] = tmp[i-1]+tmp[i-2];
return tmp[n];
}
//Cách 2: sử dụng quy hoạch động
//Lưu trữ kết quả trong các (3) biến đơn
//Độ phức tạp: O(n)
long F2(int n) {
long t2, t1, t;
if (n<=2) return 1;
t2 = t1 = 1;
for(int i=3; i<=n; i++)
{
t = t2+t1;
t2 = t1;
t1 = t;
}
return t;
}
6. Giai thừa :
//Dùng quy hoạch động, mảng 1 chiều
long GT1(int n) {
if (n<1) return 1; //đơn giản
long *F; //mảng cấp phát động
F = new long[n+1];
if (F==NULL) return 0; //lỗi cấp phát
F[0] = 1;
//Tính GT(n)
for(int i=1; i<=n; i++)
F[i] = i*F[i-1];
long t = F[n];
delete F;
return t;
}
//Quy hoạch động, dùng 2 biến
long GT2(int n) {
if (n<1) return 1; //đơn giản
long f1, f;
f1 = 1; //ban đầu
for(int i=1; i<=n; i++){
f = f1*i;
f1 = f;
}
return f;
}
//Quy hoạch động, dùng 1 biến
long GT3(int n) {
if (n<1) return 1; //đơn giản
long f=1;
for(int i=1; i<=n; i++)
f = f*i;
return f;
}
7. Tổ hợp :
int TinhToHop1D(int a[MAX],int n,int k)
{
for(int i=0;i<n;i++)
a[i]=0;
int tam,tam1;
a[0]=1;
//in
for(int q=0;q<=n;q++)
printf("%4d ",a[q]);
printf("\n");
//tính toán
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
if(j==1){
tam=a[j];
a[j]=a[j]+a[j-1];
}
else{
tam1=a[j];
a[j]=a[j]+tam;
tam=tam1;
}
}
//in
for(int q=0;q<=n;q++)
printf("%4d ",a[q]);
printf("\n");
}
return a[k];
}
int TinhToHop2D(int a[MAX],int b[MAX],int n,int k)
{
for(int i=0;i<=n;i++)
a[i]=0;
a[0]=1;
//in KQ
for(int q=0;q<=n;q++)
printf("%4d ",a[q]);
printf("\n");
//
for(int i=1;i<=n;i++)
{
b[0]=1;
for(int j=1;j<=i;j++)
b[j]=a[j]+a[j-1];
for(int ka=0;ka<=n;ka++)
a[ka]=b[ka];
//in KQ
for(int q=0;q<=n;q++)
printf("%4d ",a[q]);
printf("\n");
}
return a[k];
}
8. Phân tích số :
//Bài toán phân tích số
//trả về số cách phân tích số n thành tổng
long phantichso(int n) {
long F[MAX][MAX];
int m, v;
for(int j=0; j<=n; j++)//khởi tạo
F[0][j] = 0;
F[0][0] = 1;
for(m=1; m<=n; m++)//số hàng lưu kết quả
for(v=0; v<=n; v++)//số cột
if (v<m)
F[m][v] = F[m-1][v];
else
F[m][v] = F[m-1][v] + F[m][v-m];
return F[n][n];
}
long QHD2Dphantichso(int n)
{
long F[2][MAX];
int m,v;
for(int j=0; j<=n; j++)//khởi tạo
F[0][j] = 0;
F[0][0] = 1;
//số hàng chỉ còn 2 hàng là [0][v] và [1][v]
for(m=1; m<=n; m++)//số hàng lưu kết quả
{
for(v=0; v<=n; v++)//số cột
{
if (v<m)
F[1][v] = F[0][v];
else
F[1][v] = F[0][v] + F[1][v-m];
}
for(int k=0;k<=n;k++)
F[0][k]=F[1][k];
}
return F[1][n];
}
long QHD1Dphantichso(int n)
{
long F[MAX];
int m,v;
for(int j=0; j<=n; j++)//khởi tạo
F[j] = 0;
F[0] = 1;
//số hàng chỉ còn 2 hàng là [0][v] và [1][v]
for(m=1; m<=n; m++)//số hàng lưu kết quả
{
for(v=0; v<=n; v++)//số cột
{
if (v<m)
F[v] = F[v];
else
F[v] = F[v] + F[v-m];
}
for(int k=0;k<=n;k++)
F[k]=F[k];
}
return F[n];
}
9. Dãy con tăng dài nhất :
//Đầu vào: dãy a[] có n phần tử
//Đầu ra: dãy L[] chứa độ dài các dãy con tăng
// dãy T[] dùng để truy vết
void daytang(int a[], int n, int L[], int T[])
{
//Định nghĩa giá trị VÔ CÙNG
int MAX_INT;
MAX_INT = (int)pow(2.0,31)-1; //2^31-1
//Chèn thêm giá trị -VC và +VC vào đầu và cuối dãy a
memmove(a+1,a,n*sizeof(int));
a[0] = -MAX_INT;
a[n+1] = MAX_INT;
//inm(a,n+2);
int i,j,jmax;
L[n+1] = 1; //điền ngược từ cuối lên đầu dãy
for(i=n; i>=0; i )
{ //Tìm vị trí max của mảng L[] từ i+1 đến n+1,
//có a[j]>a[i]
jmax = n+1;
for(j=i+1; j<=n+1; j++)
if (a[j]>a[i] && L[j]>L[jmax])
jmax = j;
//ghi nhận lại giá trị cho L[i] và T[i]
L[i] = L[jmax]+1;
T[i] = jmax;
}
}
10. Sudoku:
//hamkiem tra dong
int ktdong(int a[][MAX], int k)
{
for(int i=0; i<8; i++)
for(int j=i+1; j<9; j++)
if (a[k][i] && a[k][i]==a[k][j])
return 1;
return 0;
}
//kiem tra cot
int ktcot(int a[][MAX], int k)
{
for(int i=0; i<8; i++)
for(int j=i+1; j<9; j++)
if (a[i][k] && a[i][k]==a[j][k])
return 1;
return 0;
}
//kiem tra vung 3x3 thu k
int kt3x3(int a[MAX][MAX],int k)
{
int m[9];//mang phu
int d=3*(k/3)+1,c=3*(k%3)+1;//tinh vi tri o giua vung 3x3
int v=0;
//chuyen vung 3x3 thanh mang 1 chieu
for(int i=-1;i<=1;i++)
for(int j=-1;j<=1;j++)
{
m[v++]=a[d+i][c+j];
}
//kiem tra vi pham
for( i=0; i<8; i++)
for(int j=i+1; j<9; j++)
if (m[i] && m[i]==m[j])
return 1;
return 0;
}
// tim dong co it o trong nhat
int DongItOTrongNhat(int a[MAX][MAX])
{
int dem=0,vt=-1,min=-1;
for(int i=0;i<9;i++)
{
for(int j=0;j<9;j++)
{
if(a[i][j]==0)
dem++;
}
if(dem>=1)
if(min==-1)
{
min=dem;
vt=i;
}
else
if(dem<min)
{
min=dem;
vt=i;
}
dem=0;
}
return vt;
}
//tim cot co it o trong nhat
int CotItOTrongNhat(int a[MAX][MAX])
{
int dem=0,vt=-1,min=-1;
for(int j=0;j<9;j++)
{
for(int i=0;i<9;i++)
{
if(a[i][j]==0)
dem++;
}
if(dem>=1)
if(min==-1)
{
min=dem;
vt=j;
}
else
if(dem<min)
{
min=dem;
vt=j;
}
dem=0;
}
return vt;
}
//tim vung 3x3 co it o trong nhat
int Vung3x3ItOTrongNhat(int a[MAX][MAX])
{
int m[9];//mang phu
int dem=0,min=-1,vt=-1;
for(int k=0;k<9;k++)
{
int d=3*(k/3)+1,c=3*(k%3)+1;//tinh vi tri o o gius vung 3x3
int v=0;
//chuyen vung 3x3 thanh mang 1 chieu
for(int i=-1;i<=1;i++)
for(int j=-1;j<=1;j++)
{
m[v++]=a[d+i][c+j];
}
//dem so o so 0 trong mang 1 chieu hay vung 3x3
for( i=0;i<9;i++)
{
if(m[i]==0)
dem++;
}
//tim min
if(dem>=1)
if(min==-1)
{
min=dem;
vt=k;
}
else
if(min>dem)
{
min=dem;
vt=k;
}
dem=0;
}
return vt;
}
void TimOTrongDienThem(int a[MAX][MAX],int &vti,int &vtj,int &vtv,
int &soD)
{
int flag=0;
vtv=-1;
//tim o cac dong
int dem=0,vt=-1,min=-1,tong=0,nho=-1;
for(int i=0;i<9;i++)
{
for(int j=0;j<9;j++)
{
tong+=a[i][j];
if(a[i][j]==0)
{
dem++;
nho=j;
}
}
if(dem==1)//chi co 1 o trong
{
soD=45-tong;
vti=i;
vtj=nho;
//return;
printf("\nVi tri [%d,%d] dien chu so
%d !\n",vti,vtj,soD);
flag=1;
}
tong=0;
dem=0;
}
//tim o cac cot
dem=0;vt=-1;min=-1,nho=-1;
for(int j=0;j<9;j++)
{
for(int i=0;i<9;i++)
{
tong+=a[i][j];
if(a[i][j]==0)
{
dem++;
nho=i;
}
}
if(dem==1)
{
soD=45-tong;
vti=nho;
vtj=j;
//return;
printf("\nVi tri [%d,%d] dien chu so
%d !\n",vti,vtj,soD);
flag=1;
}
dem=0;
tong=0;
}
//tim tren vung 3x3
int m[MAX];//mang phu
dem=0;
for(int k=0;k<9;k++)
{
int d=3*(k/3)+1,c=3*(k%3)+1;//tinh vi tri o giua vung 3x3
int v=0,luuvt=-1;
tong=0;
//chuyen vung 3x3 thanh mang 1 chieu
for(int i=-1;i<=1;i++)
for(int j=-1;j<=1;j++)
{
m[v++]=a[d+i][c+j];
}
//dem so o so 0 trong mang 1 chieu hay vung 3x3
for( i=0;i<9;i++)
{
tong+=m[i];//timtong tat cac so trong vung 3x3
if(m[i]==0)
{
dem++;
luuvt=i;
}
}
if(dem==1)
{
soD=45-tong;
for(int i=-1;i<=1;i++)
for(int j=-1;j<=1;j++)
{
if(a[d+i][c+j]==0)
{
vti=d+i;
vtj=c+j;
vtv=k;
}
}
printf("\nVi tri [%d,%d] vung %d dien chu so
%d !\n",vti,vtj,vtv,soD);
//return;
flag=1;
}
dem=0;
tong=0;
}
if(flag==0)
printf("\nKhong tim thay vi tri chac chan nao thoa
man !!!\n");
}
//tim so co the dien them
void SoCoTheDienThem(int a[MAX][MAX],int &vti,int &vtj,int &vtv, int
&soD)
{
int dem=0,tongi=0,tongj=0,flag=0;
for(int so=1;so<10;so++)
{
for(int i=0;i<9;i++)
for(int j=0;j<9;j++)
{
if(a[i][j]==so)
{
tongi+=i;//tinh tong cac hang
tongj+=j;//tinh tong cac cot
dem++;//dem so chu so = so
}
}
if(dem==8)
{
soD=so;
vti=36-tongi;
vtj=36-tongj;
//return;
printf("\nVi tri [%d,%d] dien chu so
%d !\n",vti,vtj,soD);
flag=1;
}
dem=0;
tongi=0;
tongj=0;
}
if(flag==0)
printf("\nKhong tim thay so chac chan nao thoa man !!!\n");
}