Dạng bài toán Ghép cặp

Một phần của tài liệu (SKKN mới NHẤT) sử DỤNG PHƢƠNG PHÁP QUY HOẠCH ĐỘNG để GIẢI một số bài TOÁN có TÍNH TRUY hồi TRONG NGÔN NGỮ lập TRÌNH c++ (Trang 32 - 38)

1 .Cơ sở lý luận

3. Nội dung vấn đề nghiên cứu

3.3. Các bài tập áp dụng

3.3.5. Dạng bài toán Ghép cặp

Mô hình: Bài toán điển hình: (Olympic Quốc tế năm 1999.)

Cần cắm hết k bó hoa khác nhau vào n lọ xếp thẳng hàng sao cho bó hoa có số hiệu nhỏ đƣợc đặt trƣớc bó hoa có số hiệu lớn. Với mỗi bó hoa i ta biết giá trị thẩm mĩ khi cắm bó hoa đó vào lọ j là v[i, j].

Yêu cầu: Xác định một phƣơng án cắm hoa sao cho tổng giá trị thẩm mĩ là lớn nhất.

Dữ liệu vào ghi trong tệp văn bản CAMHOA.INP: -Dòng đầu tiên là hai trị k và n.

-Từ dòng thứ hai trở đi là các giá trị v[i, j] trong khoảng 0..10, với i = 1..k và j = 1..n; 1 ≤ k ≤ n ≤ 100.

Dữ liệu ra ghi trong tệp văn bản CAMHOA.OUT: dòng đầu tiên là tổng giá trị thẩm mĩ của phƣơng án cắm hoa tối ƣu. Từ dòng thứ hai là dãy k số hiệu lọ đƣợc chọn cho mỗi bó hoa.

Các số liệu vào và ra đều là số tự nhiên và đƣợc ghi cách nhau bởi dấu cách trên mỗi dòng.

Ví dụ:

Kết quả cho biết tổng giá trị thẩm mĩ sẽ đạt là 24 (điểm) nếu cắm hoa như sau: - Bó hoa 1 cắm vào lọ 1; - Bó hoa 2 cắm vào lọ 3; - Bó hoa 3 cắm vào lọ 4; - Bó hoa 4 cắm vào lọ 6. Công thức:  Xây dựng hàm mục tiêu:

Gọi T(i, j) là tổng giá trị thẩm mĩ khi giải bài toán với i bó hoa mã số 1..i và j lọ mã số 1..j, tức là độ thẩm mĩ thu đƣợc khi cắm hết i bó hoa đầu tiên vào j lọ đầu tiên, ta thấy:

- Nếu số bó hoa nhiều hơn số lọ, i > j thì không có cách cắm nào vì đầu bài yêu cầu phải cắm hết các bó hoa, mỗi bó vào đúng 1 lọ.

 Bài toán cơ sở :

T(i, j) = 0

 Xây dựng công thức:

- Nếu số bó hoa bằng số lọ (i = j) thì chỉ có một cách cắm là bó nào vào lọ đó. - Ta xét trƣờng hợp số bó hoa ít hơn hẳn số lọ (i < j). Có hai tình huống: lọ cuối cùng, tức lọ thứ j đƣợc chọn cho phƣơng án tối ƣu và lọ thứ j không đƣợc chọn.

Nếu lọ cuối cùng, lọ thứ j đƣợc chọn để cắm bó hoa (cuối cùng) i thì i -1 bó hoa đầu tiên sẽ đƣợc phân phối vào j - 1 lọ đầu tiên. Tổng giá trị thẩm mĩ s khi đó sẽ là T(i - 1, j - 1) + v[i, j].

Nếu lọ thứ j không đƣợc chọn cho phƣơng án tối ƣu thì i bó hoa phải đƣợc cắm vào j-1 lọ đầu tiên và do đó tổng giá trị thẩm mĩ sẽ là T(i, j-1).

Tổng hợp lại ta có giá trị tối ƣu khi cắm i bó hoa vào j lọ là: T(i,j) = max {T(i-1,j-1)+v[i,j],T(i,j-1)}

Độ phức tạp của thuật toán là: O(k.n)

Cài đặt chƣơng trình:

#include <bits/stdc++.h>

#define fo(i,a,b) for(int i=a; i<= b; i++)

CAMHOA.INP CAMHOA.OUT 4 6 1 1 6 4 3 10 9 1 4 7 2 7 7 2 6 10 2 3 6 10 7 1 3 9 24 1 3 4 6

#define fd(i,a,b) for(int i=a;i>=b;--i) #define Fill(s,a) memset(s,a,sizeof(s)); using namespace std;

typedef long long ll;

typedef unsigned long long ull; const int K1 = 1001;

const int N1 = 1001; ll n, k;

ll v[K1][N1],L[K1][N1]={},T[K1][N1]={};

*/Tinh tong trong truong hop luong hoa = so luong binh long long sum(int x)*/

{ ll d = 0; fo(i,1,x) { d = d + v[i][i]; } return d; } int main() { freopen("camhoa.inp","r",stdin); freopen("camhoa.out","w",stdout); cin>>k; cin>>n; fo(i,1,k) {

fo(j,1,n) cin>> v[i][j]; } fo(i,1,k) { fo(j,i,n) if (i==j){L[i][j]=sum(i); T[i][i]=1;} else {if (L[i-1][j-1]+v[i][j]>L[i][j-1]) {L[i][j]=L[i-1][j-1]+v[i][j];T[i][j]=1; }

//Danh dau viec cam hoa i vao lo j else {L[i][j]=L[i][j-1];} }

}

cout<<"Tong gia tri tham my la :"<<L[k][n]<<endl; //Truy vet cach cam hoa

cout<<"Thu tu cac hoa duoc cam la: "; int a[N1];

int i1=k,j1=n,t=0; while ((i1>=1)) {

if (T[i1][j1]==1) {t++;a[t]=j1; j1=j1-1;i1=i1-1;} else {j1=j1-1;} } fd(i,t,1) cout<<a[i]<<" "; return 0; } Bài toán cùng dạng:

Đề bài: (Học sinh giỏi Tin học, Hà Nội, năm 2000)

Cần bố trí k nhóm học sinh vào k trong số n phòng học chuyên đề sao cho nhóm có số hiệu nhỏ đƣợc xếp vào phòng có số hiệu nhỏ hơn phòng chứa nhóm có số hiệu lớn. Với mỗi phòng có nhận học sinh, các ghế thừa phải đƣợc chuyển ra hết, nếu thiếu ghế thì phải lấy từ kho vào cho đủ mỗi học sinh một ghế. Biết số học sinh trong mỗi nhóm và số ghế trong mỗi phòng. Hãy chọn phƣơng án bố trí sao cho tổng số lần chuyển ghế ra và chuyển ghế vào là ít nhất.

+ Công thức:

Khi xếp nhóm i vào phòng j thì số lần chuyển ghế chính là độ chênh lệch giữa số ghế trong phòng j và số học sinh trong nhóm i. Đặt V[i,j]=|Ai−Bj|, là tổng số ghế cần chuyển ra vào khi nhóm học sinh i vào phòng j. Bài toán đƣợc quay về dạng tƣơng tự bài toán cắm hoa.

Chỉ khác ở chỗ T(i,j) = min {T(i-1,j-1)+v[i,j],T(i,j-1)}.

+ Cài đặt chƣơng trình:

#include <bits/stdc++.h>

#define fd(i,a,b) for(int i=a;i>=b;--i) using namespace std;

typedef long long ll;

typedef unsigned long long ull; const int K1 = 1001;

const int N1 = 1001; ll n, k;

ll A[K1],B[N1],v[K1][N1]; ll L[K1][N1]={},T[K1][N1]={};

*/Tinh tong trong truong hop so nhom = so phong long long sum(int x)*/

{ ll d = 0; fo(i,1,x) { d = d + v[i][i]; } return d; } int main() { ios_base::sync_with_stdio(false); freopen("xepphong.inp","r",stdin); freopen("xepphong.out","w",stdout); cin.tie(0); cout.tie(0); cin>>k; cin>>n; fo(i,1,k) cin>>A[i]; fo(j,1,n) cin>>B[j];

*/ Tinh lai so ghe can chuyen cua cac nhom vao cac phong */ fo(i,1,k) { fo(j,1,n) v[i][j]=abs(A[i]-B[j]); } fo(i,1,k)

{ fo(j,1,n) cout<<v[i][j]<<" "; cout<<endl; } fo(i,1,k) { fo(j,i,n) if (i==j){L[i][j]=sum(i); T[i][i]=1;} else {if (L[i-1][j-1]+v[i][j]<L[i][j-1])

{L[i][j]=L[i-1][j-1]+v[i][j];T[i][j]=1; } */Danh dau viec nhom i vao phong j */

else {L[i][j]=L[i][j-1];} }

}

cout<<"Tong so lan chuyen ghe it nhat la:"<<L[k][n]<<endl;

//Truy vet cach bo tri

cout<<"Thu tu cac nhom vao cac phong la: "; int a[N1];

int i1=k,j1=n,t=0; while ((i1>=1)) {

if (T[i1][j1]==1) {t++;a[t]=j1; j1=j1-1;i1=i1-1;} else {j1=j1-1;}

}

fd(i,t,1) cout<<a[i]<<" "; return 0;

Một phần của tài liệu (SKKN mới NHẤT) sử DỤNG PHƢƠNG PHÁP QUY HOẠCH ĐỘNG để GIẢI một số bài TOÁN có TÍNH TRUY hồi TRONG NGÔN NGỮ lập TRÌNH c++ (Trang 32 - 38)