Prerequisite knowledge: Basics of Linear Programming
Introduction
In algorithm contests, the simplex method is often used to solve linear programming problems. However, most linear programming problems encountered in contests have more special structure and can often be reduced to network flow problems. Consequently, the simplex method is not commonly used, and its efficiency is inferior to algorithms designed specifically for network flow problems.
Basic Concepts
Suppose we want to solve the linear programming problem in standard form with decision variables and constraints:
We may assume that the system of linear equations defined by these equality constraints is solvable and that has full rank, so .
An Example
Before formally describing the steps of the simplex method, we first examine a concrete example to make them easier to understand.
Example
Consider the linear programming problem
Adding slack variables gives its standard form:
Observe the equality constraints of this problem. They express the variables in terms of . Rearranging the original problem slightly gives
From this form, it is clear that setting gives a feasible solution of the original problem
with value . For convenience, call the variables set to zero, , non-basic variables, and call the remaining variables, , basic variables.
This feasible solution is clearly not optimal. We can increase appropriately while keeping nonnegative, so the solution remains feasible. Moreover, because the coefficients of in the objective function are strictly negative, increasing them decreases the objective value. For example, we can increase . To decrease the objective value as much as possible, we should increase as much as possible. To keep the solution feasible, however, we must maintain . Therefore, can be increased at most to
The feasible solution is now
Since has become a basic variable, we need to choose a new non-basic variable to return to the initial form (three basic variables expressed in terms of three non-basic variables). Since are both zero, either can be chosen as the non-basic variable and set to zero. Choose without loss of generality. Also, substitute
Substituting this into the original problem rewrites it as
This returns to the initial form.
Continue examining the current objective function. The coefficient of the non-basic variable is still negative, so we can consider increasing . To keep , can be increased at most to
Note that in the expression for , the coefficient of is positive, so no increase of can make negative. This is why the braces in this step contain only two terms. When reaches , both become zero, so either can be chosen as the new non-basic variable. Choose . Then substitute
Substituting this into the problem above transforms it into
Setting lets us read the current feasible solution from this form:
and its corresponding value is .
Repeat the previous operation. Since the coefficient of is negative, its value can be increased; but to keep nonnegative, it can only be increased to
Since the minimum in the braces occurs in the expression for , it becomes zero when . Substitute
Substituting this into the problem above rewrites the original problem as
Setting the non-basic variables to zero again gives the current feasible solution
with corresponding value .
Since all non-basic variables have positive coefficients in the objective function, the process described above can no longer improve the objective. Thus, the current feasible solution is optimal and the algorithm terminates.
In this example, the algorithm starts from a feasible solution and repeatedly improves the objective function until no further improvement is possible. This is the basic idea of the simplex method.
Basic Feasible Solutions
Since has full rank, we can always choose a subset of size , , such that is an invertible square matrix. We can then express in terms of the remaining variables :
Here, ; the matrices are the submatrices formed by the columns of with labels and , respectively, and the vectors are the subvectors of consisting of components with labels and , respectively. If , then is called a basic variable; otherwise, is called a non-basic variable. All basic variables together form a basis, denoted in this article by the corresponding label set .
“Basis”
The name “basis” can be understood from linear algebra. Let the column vectors of span a linear space . Then the column vectors corresponding to form a basis of .
In the expression for the basic variables , setting gives a solution to all equality constraints1
This solution is called a basic solution of the linear programming problem. If it also satisfies all non-negativity constraints, namely , it is a feasible solution of the original problem and is called a basic feasible solution (BFS). During simplex iterations, the current solution must always remain a basic feasible solution.
Pivoting
Each iteration of the simplex method is called a pivot. In effect, each pivot removes an old basic variable and adds a new basic variable, thereby improving the objective value.
“Pivot”
The name “pivot” can likewise be understood from linear algebra. As described above, the columns corresponding to a basis form a basis of the space ; they therefore correspond to a set of coordinate axes of the space under that basis representation. Pivoting is thus the process of rotating one coordinate axis to a new position.
To determine which basic variable to add, express the objective function in terms of the non-basic variables:
Setting gives the objective value at the current basic feasible solution. The coefficient of the second term represents the change in the objective function when changes:
Since , we can define the vector
For a feasible basic solution , this is the reduced cost of the linear programming problem. A component means that increasing can improve the objective function. Such a variable must be non-basic and is called the entering variable for this pivot. After the pivot, becomes basic and is no longer fixed at zero, although it may still be zero.
After choosing the entering variable, we must choose the old basic variable to remove. We only need to determine which current basic variable first becomes zero as increases. Substitute into the expression for to obtain
Therefore, the maximum amount by which can be increased is
The variable that becomes zero first is the basic variable corresponding to the index that attains the minimum in this expression, namely . It is the “bottleneck” in increasing : increasing further would make negative. This variable is the leaving variable for this pivot. The method for determining it is called the minimum ratio test.
Let the entering variable be and the leaving variable be . After pivoting, the basic variables are and the non-basic variables are .
Termination Conditions
The simplex method starts from a basic feasible solution and repeatedly pivots. The discussion of pivoting in the previous section was not complete because it omitted special cases. Some special cases terminate the algorithm, while others require additional handling.
First, an entering variable may not exist, that is, . Then no method can further improve the optimal value, so the current basic feasible solution is optimal and the algorithm terminates. A rigorous proof uses the complementary slackness conditions. Let . Throughout the algorithm, remains feasible and complementary slackness holds:
Therefore, it suffices for to be feasible for the dual problem, namely , to conclude that and are optimal solutions of the primal and dual problems, respectively. This condition is exactly , meaning that no entering variable exists.
“Shadow Price”
The vector is often called the dual vector. When the basic feasible solution corresponding to is optimal for the primal problem, is an optimal solution of the dual problem as well. Thus, solving the primal problem by the simplex method also yields an optimal solution to the dual problem. Since is the partial derivative of the current value with respect to the constraint constants, namely
It is also called the shadow price.
Second, a leaving variable may not exist, that is, . Then there is no “bottleneck” during pivoting: we can keep increasing to improve the objective until it equals . This means that the given linear programming problem is unbounded, and the algorithm terminates.
Finally, the entering and leaving variables may not be unique. An inappropriate choice may cause too many pivots or even make the algorithm enter a cycle and fail to terminate. Handling these cases is somewhat more complex; some pivot rules are needed to avoid cycles and reduce the number of pivots.
Simplex Tableau
When implementing pivots, we only need to maintain the coefficient matrix of the linear programming problem after each pivot:
It corresponds to the linear programming problem:
The matrix is called the condensed simplex tableau of the linear programming problem with respect to basis . Its upper-left entry is the value of the current solution (with the opposite sign); the quantity in row , column , , is the reduced cost of the -th non-basic variable ; the quantity in row , column , , is the value of the -th basic variable ; and consists of the coefficients obtained by using the non-basic variables to express the basic variables .
It is easy to see that all information needed for a pivot can be obtained directly from the condensed simplex tableau. Specifically, one pivot consists of:
- Select a column with . If no such exists, the current solution is optimal, and is the optimal value.
- Select a row such that and is minimal. If no such exists, the original problem is unbounded.
- Make entering and leaving, then update the simplex tableau.
Now let us discuss specifically how to update the simplex tableau. Before the update, row represents the equation
To update the tableau, express in terms of , namely:
Substituting this into the other equations gives
Row is similar, except that the left side of the equation becomes . Although the formulas look complicated, the implementation only needs two steps:
- Update row : let , set the number in column to , and divide every number in the row by ;
- Update every row : let , set the number in column to , and subtract times row from the entire row.
“Simplex Tableau”
The simplex tableau is the matrix
Compared with the condensed simplex tableau, it has additional columns, corresponding respectively to the basic variables; the column corresponding to the -th basic variable is always , meaning that in row this vector takes the value , while in every other row it takes the value . Since these columns provide no additional information, they are often omitted when implementing the simplex method, yielding the condensed simplex tableau.
The simplex tableau makes the tableau-update steps easier to understand. Every tableau can be obtained by left-multiplying the same matrix by an invertible matrix determined by the basis:
Thus, these tableaux and can be converted into one another by a sequence of elementary row operations. Therefore, when updating the tableau, it suffices to perform elementary row operations so that the column corresponding to the entering variable becomes . Transferring these operations to the condensed tableau gives the steps above.
The reference implementation for updating the condensed simplex tableau is as follows:
Reference Implementation
// Pivot on (N[x], B[y]).
void pivot(int x, int y) {
std::swap(N[x], B[y]);
long double v = -1 / tab[x][y];
for (int j = 0; j <= m + 1; ++j) {
tab[x][j] = j == y ? -v : v * tab[x][j];
}
for (int i = 0; i <= n; ++i) {
if (i == x) continue;
v = tab[i][y];
tab[i][y] = 0;
for (int j = 0; j <= m + 1; ++j) {
tab[i][j] += v * tab[x][j];
}
}
}
This implementation shows that a single simplex-tableau update takes time. As discussed later in pivot rules, determining the leaving and entering variables also takes at most time, so a single pivot takes time.
For clarity, we list here the detailed steps for computing the example above using the condensed simplex tableau.
Example (continued)
Initially, the condensed simplex tableau is as follows:
Based on the reduced costs in row , we can choose to enter. Let enter. The minimum ratio test then allows us to choose to leave. Let leave. The updated condensed tableau is:
Based on the reduced costs in row , we can choose to enter. Let enter. The minimum ratio test then allows us to choose to leave. Let leave. The updated condensed tableau is:
Based on the reduced costs in row , only can enter. Let enter. The minimum ratio test allows only to leave. Let leave. Using the elementary row operations above, the updated tableau is:
Since there is no entering variable according to the reduced costs in row , the current solution
is optimal; the optimal value (for the minimization problem) is .
Besides implementing the simplex method with a simplex tableau, one can use the revised simplex method, which further improves the time and space complexity and reduces the complexity of one update to . It is especially efficient when or is sparse.
Geometric Background
This section introduces the geometric background of the simplex method.
For the feasible region of the linear programming problem
the analysis shows that:
- An optimal solution to a linear programming problem, if one exists, can always be chosen as a vertex of the feasible region . Solving the linear programming problem therefore reduces to finding, among all vertex solutions, the one with the optimal value.
- The coordinates of every vertex can be obtained by solving the system formed by tight constraints. For standard-form constraints, all equality constraints are necessarily tight, and the remaining constraints must be selected from the non-negativity constraints. Choosing these non-negativity constraints as tight constraints is equivalent to setting the corresponding decision variables to . The system then reduces, in the remaining decision variables , to the linear system . If is invertible, we obtain . This gives a solution ; if , these are the coordinates of a vertex of .
It is easy to see that the notion of a vertex solution agrees with the basic feasible solution defined above. Thus, finding the best basic feasible solution yields an optimal solution to the original problem. Although this greatly simplifies the problem, the number of vertices of the feasible region is exponential, so exhaustive search is impractical.
To overcome this difficulty, consider moving along an edge of the feasible region from one vertex to an adjacent vertex. Since adjacent vertices lie on the same edge, they satisfy at least common tight constraints. In other words, the tight constraints corresponding to adjacent vertices differ in exactly one constraint. Therefore, for a basic feasible solution , replacing one basic variable with one non-basic variable yields an adjacent basic feasible solution . This is precisely a pivot.
Thus, the process in which the simplex method starts from a basic feasible solution and repeatedly pivots to improve the objective is exactly the process of starting at a vertex of the corresponding feasible region and moving to adjacent vertices to improve the objective.
Example (continued)
In the example discussed here, the feasible region is a three-dimensional polyhedron with five vertices, as shown below:
Geometrically, the solution process above corresponds to the following path between vertices of the polyhedron:
Implementation Details
The simplex tableau can solve many linear programming problems. However, for the most general cases, the simplex method still has many details worth examining.
Slack Form
The method for converting a linear programming problem in general form to standard form was discussed above. To make it convenient to solve with the simplex method, we also need the coefficient matrix to have full rank. Although converting to standard form and then removing linearly dependent constraints works, the following strategy is usually used for simplicity:
- Convert the linear programming problem to inequality form, namely ;
- Add slack variables to obtain standard form: .
The advantage is that the coefficient matrix of the resulting standard form is always full rank, and a (not necessarily feasible) basic solution always exists. This special standard form is called slack form.
Initial Basic Feasible Solution
The simplex method described above always assumes that a basic feasible solution is known. Sometimes one is easy to find. For example, if in the slack form above, then is a basic feasible solution. This is the situation in the numerical example above.
For the general case, use the two-phase method. It performs the simplex method twice. The first phase solves a feasibility linear program and obtains a basic feasible solution of the original problem. The second phase starts from this basic feasible solution and applies the simplex method to solve the original problem.
Suppose the problem is in standard form . In the first phase, solve
This is a feasibility linear program. The newly added variable is called an artificial variable. It has the basic feasible solution , so it can be solved directly by the simplex method. If the optimum is strictly greater than , then no satisfies , so the original problem is infeasible. If the optimum equals , the artificial variables in an optimal solution must all be zero. If some artificial variables are still basic, pivot them out through several pivots. Finally, when all artificial variables are non-basic, the basic solution obtained in phase one can be used as the initial basic feasible solution for phase two.
Phase One Without Explicit Artificial Variables
When implementing phase one, it is not necessary to introduce artificial variables explicitly. For any chosen initial basis , we have
If , no artificial variable is needed; otherwise, introduce an additional artificial variable :
Let . Then the phase-one simplex tableaus are obtained from the following tableau by a sequence of elementary row operations:
As with simplifying the simplex tableau to the condensed simplex tableau, it can be simplified appropriately (left-multiply the row by , add it to row , and omit the last three columns):
This is broadly the same as the ordinary condensed simplex tableau, except that the variable in the last row is marked with a minus sign, indicating that the row still contains an artificial variable and the original slack variable is still infeasible. Using this tableau, the pivoting process is as follows:
-
If , terminate.
-
Otherwise, because the reduced cost in row is negative, choose the entering variable . If none exists, the original problem is infeasible; terminate.
-
Using column , choose a leaving variable . Again use the minimum ratio test, but require both currently feasible variables to remain feasible and currently infeasible variables to remain infeasible; choose
as the row containing the leaving variable. If several such leaving variables exist, prioritize an infeasible leaving variable.
-
Let enter and leave, then update the simplex tableau.
-
If , remove from (cancel the minus sign on that row) and add one to .
The columns containing artificial variables can be omitted because if they are still basic, their columns are and need not be recorded; if they are no longer basic, they will never enter again and also need not be recorded. When an artificial variable leaves the basis, it must be replaced by the corresponding non-artificial variable, which is exactly the purpose of the final step above.
The reference implementation is as follows:
Reference Implementation
// First phase: find an initial BFS. // Return false if no feasible solution. bool initialize() { int neg_count = 0; for (int j = 0; j < m; ++j) { if (tab[n][j] < -eps) { for (int i = 0; i <= n; ++i) { tab[i][m + 1] += tab[i][j]; } B[j] = ~B[j]; ++neg_count; } } while (neg_count) { int x = -1; long double mi = -eps; for (int i = 0; i < n; ++i) { if (tab[i][m + 1] < mi) { x = i; mi = tab[i][m + 1]; } } if (x == -1) return false; int y = -1; mi = INFINITY; for (int j = 0; j < m; ++j) { if ((B[j] < 0 && tab[x][j] < -eps) || (B[j] >= 0 && tab[x][j] > eps)) { auto tmp = tab[n][j] / tab[x][j] + (B[j] < 0 ? -eps : eps); if (tmp < mi) { y = j; mi = tmp; } } } if (B[y] < 0) { --neg_count; B[y] = ~B[y]; pivot(x, y); tab[x][m + 1] += 1; } else { pivot(x, y); } } return true; }Before phase one starts, add an extra row to record the phase-one objective function. During pivoting, pivot the entire tableau, including the phase-two objective function. Thus, when phase one is complete, the phase-two objective has also been updated accordingly, and phase two can begin directly with the simplex method.
The two-phase method can also be implemented with a single simplex method. Choose a sufficiently large positive number and directly solve
This yields the optimum of the original problem. In the implementation, is not assigned a concrete value; it is treated as an unknown sufficiently large positive number . This method is called the big method.
The Naive Algorithm Has Exponential Practical Complexity
Because the slack form always has an initial basic solution, though not necessarily a feasible one, a simple idea for finding an initial basic feasible solution is to start from an infeasible basic solution and repeatedly pivot out infeasible basic variables, choosing as the entering variable the non-basic variable in the column whose entry in the corresponding row is also negative, until all basic variables are nonnegative. The reference implementation is as follows:
Reference Implementation
// First phase: find an initial BFS.
// Return false if no feasible solution.
bool initialize() {
while (true) {
int y = -1;
long double mi = -eps;
for (int j = 0; j < m; ++j) {
if (tab[n][j] <= mi) {
y = j;
mi = tab[n][j];
}
}
// No row with a negative basic variable => Feasible.
if (y == -1) break;
int x = -1;
for (int i = 0; i < n; ++i) {
if (tab[i][y] < -eps && (x == -1 || N[i] > N[x])) {
x = i;
}
}
// No column with a negative entry => Infeasible.
if (x == -1) return false;
pivot(x, y);
}
return true;
}
Although this is simple, unlike the two-phase method it has no objective function describing how infeasible the current basis is, so it lacks a clear direction for improvement. In practice, compared with methods that usually need only pivots, namely the two-phase method or the big method, this naive algorithm usually needs pivots and can easily enter cycles when are large. Although the constant factor in the number of pivots is small, the naive algorithm is only suitable for .
Pivot Rules
During pivoting, if there are multiple choices for entering or leaving variables, use a pivot rule to choose which variables enter or leave. With a simplex tableau, every rule discussed here can find the entering and leaving variables in time, so one pivot still takes time.
The choice of entering variable often determines the number of pivots before termination. Common rules include:
- Choose the first entering variable found;
- Choose the entering variable with the smallest label (part of Bland's rule);
- Choose the entering variable with the largest absolute reduced cost (that is, ; Dantzig's rule);
- Choose the entering variable with the largest single-pivot improvement in the objective (that is, );
- Choose the entering variable corresponding to the steepest edge, namely the largest objective improvement per unit distance along the edge (that is, );
- Choose an entering variable at random.
In practice, the steepest-edge rule is the most efficient2. It is generally believed that a suitable pivot rule finds an optimal solution for most problems in roughly pivots. However, every currently known pivot rule has specially constructed examples3 that force the number of pivots to be exponential. This is why the simplex method performs quite well in practice but has exponential worst-case complexity in theory.
The choice of leaving variable often determines whether the algorithm enters a cycle. If several basic feasible solutions have the same optimal value, the algorithm may cycle among them indefinitely. Such cases are uncommon, so many simplex implementations do not specify a rule for choosing the leaving variable. Two common anti-cycling rules are:
-
Bland's rule: always choose the entering and leaving variables with the smallest labels.
-
Lexicographic rule: always choose a row with and
the leaving variable corresponding to the lexicographically smallest row index , namely . The choice of entering variable is unimportant.
If the linear programming problem is in slack form, all these quantities can be obtained directly from the tableau described above. Otherwise, after finding an initial basic solution (not necessarily feasible), use the coefficients in the columns corresponding to the basic variables of this initial basis (with the order fixed) as the coefficients of .
Bland's rule is inefficient because it uses the same method to choose entering and leaving variables, which can easily cause the same variable to enter and leave repeatedly. The lexicographic rule is more practical. It is equivalent to perturbing the parameters of the linear programming problem4, so no two basic feasible solutions have the same optimal value and cycling is impossible.
Reference Implementation
This section provides a reference implementation of the two-phase simplex method based on the condensed simplex tableau.
Luogu P13337 [Template] Linear Programming
#include <algorithm>
#include <climits>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <vector>
// --8<-- [start:core]
int m, n; // Number of constraints and variables.
std::vector<std::vector<long double>>
tab; // Compressed tableau (transposed) with
// first-phase objective attached.
std::vector<int> B, N; // Basic and nonbasic variables.
constexpr long double eps = 1e-12l; // Precision.
// --8<-- [start:pivot]
// Pivot on (N[x], B[y]).
void pivot(int x, int y) {
std::swap(N[x], B[y]);
long double v = -1 / tab[x][y];
for (int j = 0; j <= m + 1; ++j) {
tab[x][j] = j == y ? -v : v * tab[x][j];
}
for (int i = 0; i <= n; ++i) {
if (i == x) continue;
v = tab[i][y];
tab[i][y] = 0;
for (int j = 0; j <= m + 1; ++j) {
tab[i][j] += v * tab[x][j];
}
}
}
// --8<-- [end:pivot]
// --8<-- [start:initialize]
// First phase: find an initial BFS.
// Return false if no feasible solution.
bool initialize() {
int neg_count = 0;
for (int j = 0; j < m; ++j) {
if (tab[n][j] < -eps) {
for (int i = 0; i <= n; ++i) {
tab[i][m + 1] += tab[i][j];
}
B[j] = ~B[j];
++neg_count;
}
}
while (neg_count) {
int x = -1;
long double mi = -eps;
for (int i = 0; i < n; ++i) {
if (tab[i][m + 1] < mi) {
x = i;
mi = tab[i][m + 1];
}
}
if (x == -1) return false;
int y = -1;
mi = INFINITY;
for (int j = 0; j < m; ++j) {
if ((B[j] < 0 && tab[x][j] < -eps) || (B[j] >= 0 && tab[x][j] > eps)) {
auto tmp = tab[n][j] / tab[x][j] + (B[j] < 0 ? -eps : eps);
if (tmp < mi) {
y = j;
mi = tmp;
}
}
}
if (B[y] < 0) {
--neg_count;
B[y] = ~B[y];
pivot(x, y);
tab[x][m + 1] += 1;
} else {
pivot(x, y);
}
}
return true;
}
// --8<-- [end:initialize]
// --8<-- [start:simplex]
// Second phase: find an optimal BFS.
// Return false if the problem is unbounded.
bool simplex() {
while (true) {
int x = -1;
long double mi = -eps;
for (int i = 0; i < n; ++i) {
if (tab[i][m] < mi) {
x = i;
mi = tab[i][m];
}
}
// No column with a negative reduced cost => Optimal.
if (x == -1) break;
int y = -1;
mi = INFINITY;
for (int j = 0; j < m; ++j) {
if (tab[x][j] <= eps) continue;
if (tab[n][j] / tab[x][j] < mi) {
y = j;
mi = tab[n][j] / tab[x][j];
}
}
// No row with a positive ratio => Unbounded.
if (y == -1) return false;
pivot(x, y);
}
return true;
}
// --8<-- [end:simplex]
int solve() {
B.resize(m);
N.resize(n);
std::iota(B.begin(), B.end(), n);
std::iota(N.begin(), N.end(), 0);
return initialize() ? (simplex() ? 0 : 1) : -1;
}
// --8<-- [end:core]
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(nullptr);
std::cout << std::fixed << std::setprecision(8);
std::cin >> n >> m;
tab.assign(n + 1, std::vector<long double>(m + 2));
for (int i = 0; i < n; ++i) {
std::cin >> tab[i][m];
tab[i][m] = -tab[i][m];
}
for (int j = 0; j < m; ++j) {
for (int i = 0; i <= n; ++i) {
std::cin >> tab[i][j];
}
}
switch (solve()) {
case -1:
std::cout << "Infeasible" << std::endl;
break;
case 1:
std::cout << "Unbounded" << std::endl;
break;
case 0: {
std::cout << tab[n][m] << std::endl;
std::vector<long double> x(n);
for (int j = 0; j < m; ++j) {
if (B[j] < n) x[B[j]] = tab[n][j];
}
for (int i = 0; i < n; ++i) {
std::cout << x[i] << ' ';
}
std::cout << std::endl;
break;
}
}
return 0;
}
Examples
「NOI2008」
,Here,the . ,Here,the canofis ,withis .of,such thatof.
Note
letthe .,canis
Here,
Clearlyofrow.Therefore,Consider for:
,obtainrow,can,.for,obtainofisof.
#include <cmath>
#include <cstring>
#include <iostream>
using namespace std;
constexpr int M = 10005, N = 1005, INF = 1e9;
int n, m;
double a[M][N], b[M], c[N], v;
void pivot(int l, int e) { // function
b[l] /= a[l][e];
for (int j = 1; j <= n; j++)
if (j != e) a[l][j] /= a[l][e];
a[l][e] = 1 / a[l][e];
for (int i = 1; i <= m; i++)
if (i != l && fabs(a[i][e]) > 0) {
b[i] -= a[i][e] * b[l];
for (int j = 1; j <= n; j++)
if (j != e) a[i][j] -= a[i][e] * a[l][j];
a[i][e] = -a[i][e] * a[l][e];
}
v += c[e] * b[l];
for (int j = 1; j <= n; j++)
if (j != e) c[j] -= c[e] * a[l][j];
c[e] = -c[e] * a[l][e];
// swap(B[l],N[e])
}
double simplex() {
while (true) {
int e = 0, l = 0;
for (e = 1; e <= n; e++)
if (c[e] > (double)0) break;
if (e == n + 1) return v; // whenvnamelyis
double mn = INF;
for (int i = 1; i <= m; i++) {
if (a[i][e] > (double)0 && mn > b[i] / a[i][e]) {
mn = b[i] / a[i][e]; // fortheseeofl
l = i;
}
}
if (mn == INF) return INF; // unbounded
pivot(l, e); // l,e
}
}
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> c[i];
for (int i = 1; i <= m; i++) {
int s, t;
cin >> s >> t;
for (int j = s; j <= t; j++) a[i][j] = 1; // denotestheikindsinjwhencan
cin >> b[i];
}
cout << (int)(simplex() + 0.5);
}
Exercises
- Luogu P13337【modulo】
- UOJ#179.
- Luogu P4232 of
- Codeforces 1430 G. Yet Another DAG Problem
- AtCoder Beginner Contest 231 H - Minimum Coloring
References
- 【 + 】
- 2016
- algorithm
- Matoušek, Jiří, and Bernd Gärtner. Understanding and using linear programming. Vol. 1. Berlin: Springer, 2007.
- Inayatullah, Syed, Nasir Touheed, and Muhammad Imtiaz. "A streamlined artificial variable free version of simplex method." PloS one 10, no. 3 (2015): e0116156.
- Floudas, Christodoulos A., and Panos M. Pardalos, eds. Encyclopedia of optimization. Springer Science & Business Media, 2008.
Footnotes
-
then,for allvectoriscolumn vector, .howeveris,of ,. ↩
-
see Forrest, John J., and Donald Goldfarb. "Steepest-edge simplex algorithms for linear programming." Mathematical programming 57, no. 1 (1992): 341-374. ↩
-
ofcansee Klee, Victor, and George J. Minty. "How good is the simplex algorithm." Inequalities 3, no. 3 (1972): 159-175. ↩