Tài liệu của thầy Nguyễn Văn Hiệu: Link1, Link2 (nên xem video trước khi đọc tài liệu)
Note: (cj là hệ số, xj là kết quả chúng ta cần tìm, A là bảng đơn hình)
- Dạng chuẩn tắc:
f(x) = sum(cj * xj) -> min (với j chạy từ 1 -> n, n là số ẩn x (cơ sở + ko cơ sở))
sum(Aij * xj) = bi (với i chạy từ 1 -> m, m là số ẩn x cơ sở)
xj >= 0
- Cách đưa về dạng chuẩn tắc
1. f(x) -> max <=> -f(x) -> min
2. sum(Aij * xj) <= bi <=> sum(Aij * xj) + xNew1 = bi
3. sum(Aij * xj) >= bi <=> sum(Aij * xj) - xNew2 = bi
4. Nếu x ko có ràng buộc về dấu thì x = u - v (u, v dương)
5. ... ?
Problem: (bài toán đang ở dạng tổng quát)
3x1 + x2 + 3x3 -> max
2x1 + x2 + 3x3 <= 2
x1 + 2x2 + 3x3 <= 5
2x1 + 2x2 + x3 <= 6
x1, x2, x3 >= 0
Solution:
B1: Nhận thấy bài toán ở dạng tổng quát nên ta đưa về dạng chuẩn tắc
-3x1 - x2 - 3x3 -> min
2x1 + x2 + 3x3 + x4 = 2
x1 + 2x2 + 3x3 + x5 = 5
2x1 + 2x2 + x3 + x6 = 6
x1, x2, x3, x4, x5, x6 >= 0
B2: Lập bảng đơn hình (ở bước này ta sẽ đưa dữ liệu vào chương trình)
c = (-3, -1, -3, 0, 0, 0) // các hệ số
cb= (c4, c5, c6) // (ở ví dụ này ta có x4 -> x5 -> x6)
=> cb = (0,0,0)
tính vector delta //delta[i] = sum(aij * cbi) - cj
tính fx // fx = sum(b*cb)
while(true){
- neu vo nghiem thi ket thuc;
- neu co nghiem thi return nghiem;
- tìm cột vào
- tìm cột ra
- biến đổi ma trận sao cho cột vào thành cột ra (a, delta, b, fx biến đổi theo)
}
Code C++11: (code này được viết bởi Nguyễn Công Cường)
#include<bits/stdc++.h>
using namespace std;
vector<int> HeSo(vector<int> c, vector< vector<double>> a){
vector<int> cb;
set<pair<int, int>> sp; //dung de tim he so theo thu tu hang 1 -> hang m
for(int j=0; j<a[0].size(); j++){
int ii= -1;
for(int i=0; i<a.size(); i++){
if (a[i][j] == 1 && ii == -1){
ii= i;
}
else
if (a[i][j]) ii= -2; //co the them break de giam dpt
}
if (ii>=0) sp.insert({ii, j}); //neu la 1 cot trong ma tran don vi
}
for(auto p : sp)
cb.push_back(c[p.second]);
return cb;
}
vector<double> TinhDelta(vector<int> cb, vector<int> c, vector< vector<double>> a){
//deltai = sum(aij * cbi) - cj
vector<double> v;
for(int j=0; j<a[0].size(); j++){
double s= 0;
for(int i=0; i<a.size(); i++)
s+= a[i][j] * cb[i];
v.push_back(s-c[j]);
}
return v;
}
double TinhFx(vector<int> cb, vector<double> b){
double s= 0;
int i= 0;
for(auto val_b: b)
s += val_b * cb[i++];
return s;
}
bool VoNghiem(vector<double>delta, vector< vector<double>> a){
//neu ton tai deltaj > 0 ma aij <= 0 (voi moi i=1:m) thi vn
for(int j=0; j<delta.size(); j++)
if (delta[j] > 0){
bool check= true;
for(int i=0; i<a.size(); i++)
if (a[i][j] > 0) check= false;
if (check) return true;
}
return false;
}
bool PATU(vector<double>delta){
for(auto val:delta)
if (val > 0) return false;
return true;
}
vector<double> Nghiem(int m, vector< vector<double>> a, vector<double> b){
vector<double> x;
for(int j=0; j<a[0].size(); j++){
int ii= -1;
for(int i=0; i<a.size(); i++){
if (a[i][j] == 1 && ii == -1){
ii= i;
}
else
if (a[i][j]) ii= -2; //co the them break de giam dpt
}
if (ii>=0) x.push_back(b[ii]); //neu la 1 cot trong ma tran don vi
else x.push_back(0);
}
return x;
}
int TimCotVao(vector<double>delta){
double valMax= delta[0];
int index= 0;
for(int i=1; i<delta.size(); i++){
if (valMax < delta[i]){
valMax= delta[i];
index= i;
}
}
return index;
}
int TimCotRa(int jVao, vector<vector<double>>a, vector<double> b, int &iVao){
double valMin= (a[0][jVao]<=0 ? 100111000 : b[0]*1.0 / a[0][jVao]);
for(int i=1; i<a.size(); i++){
if (a[i][jVao] <= 0) continue;
double tiSoKoAm= b[i]*1.0 / a[i][jVao];
if (valMin > tiSoKoAm){
valMin= tiSoKoAm;
iVao= i;
}
}
for(int j=0; j<a[0].size(); j++)
if (j != jVao){
int ii= -1;
for(int i=0; i<a.size(); i++){
if (a[i][j] == 1 && ii == -1){
ii= i;
}
else
if (a[i][j]) ii= -2; //co the them break de giam dpt
}
if (ii == iVao) return j;
}
return -1; //error
}
void output(vector<int> c, vector<int> cb, vector<vector<double>> a, vector<double> delta, double fx, vector<double> b){
cout<<"\n\n-----------------------BANG DON HINH--------------------------------\n\n";
cout<<setw(10)<<""; for(auto val: c) cout<<setw(10)<<val; cout<<setw(10)<<" <-- [c]";
cout<<"\n";
int i= 0;
for(auto v : a){
cout<<"\n";
cout<<setw(10)<<cb[i];
for(auto val : v)
cout<<setw(10)<<fixed<<setprecision(1)<<val;
cout<<setw(10)<<b[i++];
}
cout<<"\n";
cout<<setw(10)<<"[cb]";
cout<<"\n";
cout <<setw(10)<<"[delta"; for(auto val:delta) cout<<setw(10)<<fixed<<setprecision(1)<<val; cout<<"]"<<setw(10)<<fixed<<setprecision(1)<<fx<<"=fx\n";
cout<<"\n\n-------------------------------------------------------------------------\n\n";
}
vector<double> process(int n, vector<int> c, int m, vector< vector<double>> a, vector<double> b){
vector<int> cb= HeSo(c, a);
vector<double> delta = TinhDelta(cb, c, a);
double fx = TinhFx(cb, b);
int cnt= 0;
while(true){
if (VoNghiem(delta, a)){
cout<<"Bai toan vo nghiem!";
exit(0);
}
if (PATU(delta)) return Nghiem(m, a, b);
int jv= TimCotVao(delta);
int iv= 0;
int jr= TimCotRa(jv, a, b, iv);
//bien doi ma tran a va vector b
double soNhan= 1 / a[iv][jv];
for(int j=0; j<a[0].size(); j++) a[iv][j] *= soNhan;
b[iv] *= soNhan;
for(int i=0; i<a.size(); i++)
if (i != iv){
soNhan = -a[i][jv] / a[iv][jv];
for(int j=0; j<a[i].size(); j++)
a[i][j] += a[iv][j]*soNhan;
b[i] += b[iv] * soNhan;
}
//bien doi vector delta
soNhan= -delta[jv] / a[iv][jv];
for(int j= 0; j<a[0].size(); j++)
delta[j] += a[iv][j] * soNhan;
fx += b[iv] * soNhan;
output(c, cb, a, delta, fx, b);
}
return vector<double>();
}
void input(){
freopen("input.txt","r",stdin);
//cout<<"nhap n (so an x (co so + ko co so)) : ";
int n; cin >> n;
vector<int> c(n);
for(int i=0; i<n; i++){
//cout<<"nhap c"<<i<<" : ";
cin >> c[i];
}
//cout<<"nhap m (so an x (co so)): ";
int m; cin >> m;
vector< vector<double> > a(m, vector<double>(n));
vector<double> b(m);
for(int i=0; i<a.size(); i++){
for(int j=0; j<a[i].size(); j++){
//cout<<"nhap a"<<i<<j<<" : ";
cin >> a[i][j];
}
//cout<<" sum(Aij * xj) = bi, nhap b"<<i<<" : ";
cin >> b[i];
}
vector<double> x= process(n, c, m, a, b);
cout<<"VAY NGHIEM TOI UU LAN LUOT LA: \n";
for(int i=0; i<x.size(); i++)
cout<<"x"<<i<<" = "<<x[i]<<"\n";
}
int main(){
input();
}
Test: (bỏ freeopen nếu nhập xuất từ console)
6
0 1 -3 0 2 0
3
1 1 -1 0 1 0 7
0 -4 4 1 0 0 12
0 -5 3 0 1 1 10
(tren la bai tap 3 trong tài liệu thầy Hiệu)
Output bài tập 3:
Bài toán vô nghiệm
6
1 -1 0 -2 2 -2
3
1 0 0 1 1 -1 2
0 1 0 1 0 1 12
0 0 1 2 4 3 9
(tren la bai tap 2)
Ouput của bài tập 2:
4
-5 -8
2
1 2 1 0 1
1 1 0 1 2
(tren la bai tap 1)
4
3 -1 2 -2
2
1 1 0 -2 1
0 -2 1 3 1
(tren la vi du 2 cua thay)
6
5 4 5 2 1 3
3
2 4 3 1 0 0 52
4 2 3 0 1 0 60
3 0 1 0 0 1 36
(tren la vi du 1 cua thay)
5
-8 0 1 1 0
3
-2 0 0 1 1 4
1 1 0 -1 0 2
1 0 1 2 0 1
(video 5)
6
-3 -1 -3 0 0 0
3
2 1 1 1 0 0 2
1 2 3 0 1 0 5
2 2 1 0 0 1 6
(video 5)