Sáng tạo trong thuật toán và lập trình với ngôn ngữ Pascal và C# - Tập 3 - Chương 5: Luyện tập từ các đề thi
Nhận xét 1. Ta có thể giảm mọi phần tử của a và b xuống 1 đơn vị. Khi đó công thức tính cisẽ được rút
gọn thành ci = siti.
Nhận xét 2. Muốn đạt trị tối ưu cmin thì trong nhóm cuối cùng, nhóm thứ k của a và b không thể chứa
đồng thời hơn 1 phần tử.
Thật vậy, gỉa sử hai nhóm cuối của dãy a và b, nhóm thứ k, đều chứa hơn 1 phần tử. Ta gọi phương án này
là P
1. Ta xây dựng phương án P
2 gồm k+1 nhóm như sau. Tách hai nhóm cuối của a và b thành hai nhóm
nhỏ và gọi tổng của các nhóm đó lần lượt là A+B cho nhóm của dãy a và C+D cho nhóm của dãy b. Khi đó
(A+B)(C+D) = AC + AD + BC + BD > AC + BD.
[0..mn] of integer;
var a,b,c,d: mi1;
n, m: integer;
function Min(a, b, c: integer): integer;
begin
if a > b then a := b;
if a < c then Min := a else Min := c;
end;
function Cmin: integer;
var i,j: integer;
begin
fillchar(c,sizeof(c),0); d := c;
{ Khoi tri: 2 day a[1] , b[1..m] }
for j := 1 to m do c[j] := c[j-1] + a[1]*b[j];
for i := 2 to n do
begin
d[1] := c[1] + a[i]*b[1];
for j := 2 to m do
d[j] := Min(c[j-1], c[j],d[j-1]) + a[i]*b[j];
c := d;
end;
Cmin := d[m];
end;
procedure Doc;
var i: integer;
f: text;
begin
assign(f,fn); reset(f);
read(f,n,m); writeln(nl,n, bl, m);
for i := 1 to n do
begin
read(f,a[i]); dec(a[i]); write(a[i],bl);
end;
writeln;
for i := 1 to m do
begin
read(f,b[i]); dec(b[i]); write(b[i],bl);
end;
close(f);
end;
procedure Ghi(v: integer);
var g: text;
begin
assign(g,gn); rewrite(g);
writeln(g,v); close(g);
end;
BEGIN
Doc;
Ghi(Cmin);
writeln(nl,' Fini');
readln;
END.
// DevC++: game.cpp
#include
#include
#include
using namespace std;
const int mn = 201;
const char * fn = "vova.inp";
const char * fn = "vova.out";
int a[mn], b[mn], c[mn], d[mn];
int n, m;
void Doc();
int Cmin();
int Min(int, int, int);
void Ghi(int);
main() {
Doc(); Ghi(Cmin());
cout << endl << " Fini "; cin.get();
return 0;
}
int Min(int x, int y, int z) {
if (x > y) x = y;
return (x < z) ? x : z;
}
int Cmin() {
int i,j;
memset(c,0,sizeof(c)); memset(d,0,sizeof(d));
for (j = 1; j <= m; ++j) c[j] = c[j-1] + a[1]*b[j];
for (i = 2; i <= n; ++i) {
d[1] = c[1] + a[i]*b[1];
for (j = 2; j <= m; ++j)
d[j] = Min(c[j-1], c[j],d[j-1]) + a[i]*b[j];
memcpy(c,d,sizeof(d));
}
return d[m];
}
void Doc() {
ifstream f(fn);
f >> n >> m; cout << endl << n << " " << m << endl;
int i;
for (i = 1; i <= n; ++i) {
f >> a[i]; --a[i];
cout << a[i] << " ";
}
cout << endl;
for (i = 1; i <= m; ++i) {
f >> b[i]; --b[i];
cout << b[i] << " ";
}
f.close();
}
void Ghi(int v) {
ofstream g(gn);
g << v;
g.close();
}
5.18 Robots
Một khu nghiên cứu Robot có 3 phòng thí nghiệm là A, B và C bố trí trên một tuyến đường thẳng theo thứ
tự đã nêu. Mỗi phòng đều có thể có 3 loại robot thông minh là robot mũ đỏ R, robot mũ xanh B và robot
mũ xanh lá G. Người ta ra lệnh cho các robot phải tự bàn nhau để thực hiện nhiệm vụ sau đây: di chuyển
về các phòng sao cho mỗi phòng chỉ có một loại robot và năng lượng chi phí cho việc di chuyển là ít nhất.
Hãy cùng bàn với các robot để chọn một phương án tối ưu.
Dữ liệu vào: text file ROBOTS.INP
Dòng thứ nhất: hai số nguyên dương biểu thị khoảng cách AB và AC;
Dòng thứ hai: ba số nguyên dương r b g cho biết chi phí năng lượng của mỗi loại robot R, B và G để
di chuyển 1 đơn vị khoảng cách;
Dòng thứ ba: ba số nguyên không âm cho biết số lượng robot mỗi loại R, B và G trong phòng A;
Dòng thứ tư: tương tự như dòng thứ ba, chứa thông tin về phòng B;
Dòng thứ năm: tương tự như dòng thứ ba, chứa thông tin về phòng C.
Dữ liệu ra: text file ROBOTS.OUT
Dòng thứ nhất: tổng chi phí năng lượng tối thiểu cho các robot di chuyển;
Dòng thứ hai: một hoán vị của ba chữ cái R, B, G viết liền nhau cho biết phương án tối ưu bố trí các
robot vào các phòng.
Dữ liệu trên cùng dòng cách nhau qua dấu cách.
ROBOTS.INP ROBOTS.OUT Giải thích Khoảng cách AB = 1; AC = 3 trên đường thẳng
ABC;
robot R cần 3, B cần 1 và G cần 2 đơn vị năng lượng để di
chuyển 1 đơn vị khoảng cách;
Phòng A có 2 robot R, 1 robot B và 2 robot G;
Phòng B có 1 robot R, 4 robot B và 3 robot G;
Phòng C có 2 robot R, 2 robot B và 1 robot G.
Kết quả: Nếu tập hợp các robot mũ đỏ R về phòng A, các
robot mũ xanh lá G về phòng B và các robot mũ xanh B về
phòng C thì chi phí năng lượng là tối thiểu và bằng 40.
1 3
3 1 2
2 1 2
1 4 3
2 2 1
40
RGB
Thuật toán
Bài này khá dễ giải vì chỉ đòi hỏi khoàng vài chục lần tính toán đơn giản. Kí hiệu XYZ là một phương án
bố trí robot loại X vào phòng A, loại Y vào phòng B và loại Z vào phòng C. Ta có tất cả 6 phương án là
RBG, RGB, BRG, BGR, GRB và GBR. Ta tính chi phí cho mỗi phương án rồi chọn phương án với chi phí
min. Ta sử dụng các hàm hỗ trợ sau đây:
Move(r, i, j) chi phí di chuyển toàn bộ robot loại r hiện có trong phòng i sang phòng j ≠ i, i, j = A,
B, C .
PhuongAn(r1, r2, r3) – chi phí cho phương án đưa các robot loại r1 về phòng A, loại r2 về phòng
B và robot loại r3 về phòng C.
(* ROBOTS.PAS *)
uses crt;
const fn = 'ROBOTS.INP'; gn = 'ROBOTS.OUT';
bl = #32; nl = #13#10; NN = 3;
A = 1; B = 2; C = 3; { cac phong }
RR = 1; RB = 2; RG = 3; { mau mu cua robots }
type mi1 = array[0..NN] of integer;
mi2 = array[0..NN] of mi1;
var AB,AC: integer; { Khoảng cách }
energy: mi1; { energy[i] - chi phí năng lượng của robot loại i }
number: mi2;
{ number[i,j] - so luong robot loai j trong phong i }
procedure Doc;
var i,j: integer;
f: text;
begin
assign(f,fn); reset(f);
read(f,AB,AC);
write(nl,' Khoang cach: ',AB,bl,AC);
write(nl,' Nang luong: ');
for i := 1 to NN do
begin read(f,energy[i]); write(energy[i],bl); end;
writeln(nl, ' Phan bo: ');
for i := 1 to NN do
begin
writeln;
for j := 1 to NN do
begin read(f,number[i,j]); write(number[i,j],bl) end;
end;
close(f);
end;
(* Chi phi chuyen robot loai r tu phong i sang phong j *)
function Move(r, i, j: integer): integer;
var e: integer;
begin
e := energy[r]*number[i][r];
case i of
A: if (j = B) then e := e*AB
else if (j = C) then e := e*AC else e := 0;
B: if (j = A) then e := e*AB
else if (j = C) then e := e*(AC-AB) else e := 0;
C: if (j = A) then e := e*AC
else if (j = B) then e := e*(AC-AB) else e := 0;
end;
Move := e;
end;
function PhuongAn(r1, r2, r3: integer): integer;
begin
PhuongAn := Move(r1,B,A) + Move(r1,C,A)+
Move(r2,A,B) + Move(r2,C,B)+
Move(r3,A,C) + Move(r3,B,C);
end;
procedure XuLi;
var i, imin, p: integer; pa: array[1..6] of integer;
g: text;
begin
p := 1; { phuong an 1: RBG }
pa[p] := PhuongAn(RR,RB,RG);
inc(p); { phuong an 2: RGB }
pa[p] := PhuongAn(RR,RG,RB);
inc(p); { phuong an 3: BRG }
pa[p] := PhuongAn(RB,RR,RG);
inc(p); { phuong an 4: BGR }
pa[p] := PhuongAn(RB,RG,RR);
inc(p); { phuong an 5: GRB }
pa[p] := PhuongAn(RG,RR,RB);
inc(p); { phuong an 6: GBR }
pa[p] := PhuongAn(RG,RB,RR);
imin := 1;
for i := 1 to 6 do
if (pa[i] < pa[imin]) then imin := i;
assign(g,gn); rewrite(g);
writeln(g,pa[imin]);
case imin of
1: write(g,'RBG');
2: write(g,'RGB');
3: write(g,'BRG');
4: write(g,'BGR');
5: write(g,'GRB');
6: write(g,'GBR');
end;
close(g);
end;
BEGIN
Doc;
XuLi;
writeln(nl,' Fini'); readln;
END.
// DecC++: Robots.cpp
#include
#include
#include
using namespace std;
const int A = 0; // Phong 0: A
const int B = 1; // Phong 1: B
const int C = 2; // Phong 2: C
const int RR = 0; // Red Robot
const int RB = 1; // Blue Robot
const int RG = 2; // Green Robot
const int NN = 3; // So loai Robot = 3
const char * fn = "robots.inp";
const char * gn = "robots.out";
const char bl = 32;
int energy[NN]; // chi phi nag luong
int number[NN][NN];
// numer[i][j] - so luong robot loai j trong phong i
int AB, AC; // Khoang cach AB, AC
int pa[6]; // cac phuong an
void Doc() {
int i, j;
ifstream f(fn);
f >> AB >> AC;
cout << endl << "Khoang cach: " << AB << bl << AC;
cout << endl << " Nang luong: ";
for (i = 0; i < NN; ++i) {
f >> energy[i];
cout << energy[i] << bl;
}
cout << endl << " Phan bo: ";
for (i = 0; i < NN; ++i) {
cout << endl;
for (j = 0; j < NN; ++j) {
f >> number[i][j];
cout << number[i][j] << bl;
}
}
f.close();
}
int Move(int r, int from, int to) {
// chi phoi chuyen robot r tu phong i sang phong j
int e = energy[r]*number[from][r];
switch(from) {
case A: if (to == B) return e*AB;
else if (to == C) return e*AC;
case B: if (to == A) return e*AB;
else if (to == C) return e*(AC-AB);
case C: if (to == A) return e*AC;
else if (to == B) return e*(AC-AB);
}
}
int PhuongAn(int r1, int r2, int r3) {
return (Move(r1,B,A)+Move(r1,C,A)+
Move(r2,A,B)+Move(r2,C,B)+
Move(r3,A,C)+Move(r3,B,C));
}
void XuLi() {
int p, i, imin;
p = 0; // phuong an 0: RBG
pa[p] = PhuongAn(RR,RB,RG);
cout << endl << "RBG: " << pa[p];
++p; // phuong an 1: RGB
pa[p] = PhuongAn(RR,RG,RB);
cout << endl << "RGB: " << pa[p];
++p; // phuong an 2: BRG
pa[p] = PhuongAn(RB,RR,RG);
cout << endl << "BRG: " << pa[p];
++p; // phuong an 3: BGR
pa[p] = PhuongAn(RB,RG,RR);
cout << endl << "BGR: " << pa[p];
++p; // phuong an 4: GRB
pa[p] = PhuongAn(RG,RR,RB);
cout << endl << "GRB: " << pa[p];
++p; // phuong an 5: GBR
pa[p] = PhuongAn(RG,RB,RR);
cout << endl << "GBR: " << pa[p];
imin = 0;
for (i = 1; i < 6; ++i)
if (pa[i] < pa[imin]) imin = i;
ofstream g(gn);
g << pa[imin] << endl;
switch (imin) {
case 0: g << "RBG"; break;
case 1: g << "RGB"; break;
case 2: g << "BRG"; break;
case 3: g << "BGR"; break;
case 4: g << "GRB"; break;
case 5: g << "GBR"; break;
}
g.close();
}
main(){
Doc();
XuLi();
cout << endl << " Fini"; cin.get();
return 0;
}
-
Giao thừa 2010
File đính kèm:
Sáng tạo trong thuật toán và lập trình với ngôn ngữ Pascal và C# - Tập 3 - Chương 5_Luyện tập từ các đề thi.pdf

