constint N = 50; //N是n+m float a[N][N]; //系数矩阵,a[i][j]表示变量id[j]在第i个限制中的系数. a[0][i]表示目标函数, a[0][0]是目标函数常数,a[i][0]是第i个限制的b_i常数 int id[N]; //id[1...n]是系数矩阵第i列对应的变量编号,id[n+1...m]是第i个限制的基变量编号 int n, m; //变量个数(不包含转化过去的松弛变量)
//代码理解困难可能主要在于a[...][i]表示的变量是在变的.
//把变量id[idx]设为行l当基变量,(用行l消掉其他行对应id[idx]的系数) voidpivot(int l, int idx){ swap(id[n + l], id[idx]); float c = a[l][idx]; for (int i = 0; i <= n; i++) a[l][i] /= c;
//a[...][idx]列要从变量id[idx]的系数变成对应限制l基变量的系数,所以后面还特判j=idx这一列. //注意id[n+l]这个基变量本来都系数是00000100000这样的 a[l][idx] = 1 / c; for (int i = 0; i <= m; i++) { if (i == l \vert \vert !sgn(a[i][idx])) continue; float x = a[i][idx]; a[i][idx] = -a[l][idx] * x; for (int j = 0; j <= n; j++) if (j != idx) a[i][j] -= a[l][j] * x; } }
//找可行解 boolinit(){ for (int i = 1; i <= n + m; i++) id[i] = i; while (true) { int line = 1, var = 0; //找常数最小的行 for (int i = 1; i <= m; i++) if (a[i][0] < a[line][0]) line = i; //已经可行 if (sgn(a[line][0]) >= 0) returntrue; for (int i = 1; i <= n; i++) { //id[var]<id[i]是和循环i的顺序对应的,不能变,否则会死循环 //记住是找的是最大的id[var] if (sgn(a[line][i]) < 0 && (var == 0 \vert \vert (id[var] < id[i]))) { var = i; } } if (!var) returnfalse; pivot(line, var); } } boolsimplex(){ while (true) { int var = 1, line = 0, temp; float lim = inf; //找目标函数中系数最大的非基变量 for (int i = 1; i <= n; i++) if (a[0][i] > a[0][var]) { var = i; }
if (sgn(a[0][var]) <= 0) returntrue; //找变量id[var]最紧的限制 for (int i = 1; i <= m; i++) { //这里id[i]>id[line]同样是找最大的,避免死循环,且这个和上面那个保持一致(要么都最大正循环,要么都找最小反着循环) if (sgn(a[i][var]) > 0 && (temp = sgn(a[i][0] / a[i][var] - lim), (temp < 0 \vert \vert temp == 0 && (!line \vert \vert id[i] > id[line])))) { line = i; lim=a[i][0]/a[i][var]; } } if (!line) returnfalse; pivot(line, var); } } float ans[N]; intmain(){ int t; longdouble in; cin >> n >> m >> t; for (int i = 1; i <= n; i++) cin >> in, a[0][i] = in; for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) cin >> in, a[i][j] = in; cin >> in, a[i][0] = in; } if (!init()) { cout << "Infeasible" << endl; return0; } if (!simplex()) { cout << "Unbounded" << endl; return0; } cout << fixed << setprecision(10) << (longdouble)-a[0][0] << endl; //答案是-a[0][0],因为我们是把a[0][0]放在等式右边了(消元的时候用的...=b_i的b_i消的a[0][0]). if(t==0)return0; for (int i = 1; i <= m; i++) { ans[id[i + n]] = a[i][0]; } for (int i = 1; i <= n; i++) cout << fixed << setprecision(10) << (longdouble)ans[i] << " "; }