题解讲的都不清晰,甚至有点问题。
实际上,使用高斯——约旦消元法也是可以区分的。按照正常的流程处理,但当你发现没有可以替换的方程(所有的下面的方程都是0),那么这个时候跳过这个元,而不是跳过这个方程!
这是正常的GaussJordan写法:
void GaussJordan() {
for (int i = 1; i <= n; i ++) {
int swapLine = 0;// 找交换的方程
for (int j = i; j <= n; j ++) {
if (abs(mat[swapLine][i]) < abs(mat[j][i])) {
swapLine = j;
}
}
if (abs(mat[swapLine][i]) <= esp) {// 错误的点就在这里!!!
continue;
}
swap(mat[i], mat[swapLine]);
for (int ele = i + 1; ele <= n + 1; ele ++) {// 改成系数为1
mat[i][ele] /= mat[i][i];
}
mat[i][i] = 1;
for (int line = 1; line <= n; line ++) {// 消元
if (line == i) {
continue;
}
for (int ele = i + 1; ele <= n + 1; ele ++) {
mat[line][ele] -= mat[line][i] * mat[i][ele];
}
mat[line][i] = 0;
}
}
}
卡它很容易,因为当它发现自由元时会跳过这个方程,致使这个有用的方程被当做为处理过了的、没用了的方程,然后吃灰,然后就智者见智仁者见仁了awa
所以!我们要作修改:
int GaussJordan() {
int line = 1;// 表示在尝试用掉第几个方程
for (int ele = 1; ele <= n; ele ++) {
int swapL = 0;// 找交换的方程
for (int i = line; i <= n; i ++) {
if (abs(mat[i][ele]) > abs(mat[swapL][ele])) {
swapL = i;
}
}
if (abs(mat[swapL][ele]) <= esp) {// 跳过这个ele,但是不跳过这个line
continue;
}
swap(mat[line], mat[swapL]);
for (int l = 1; l <= n; l ++) {// 消元
if (l == line) {
continue;
}
for (int i = ele + 1; i <= n + 1; i ++) {
mat[l][i] -= mat[l][ele]
* mat[line][i]
/ mat[line][ele];
}
mat[l][ele] = 0;
}
line ++;
}
line --;
if (line < n) {// 如果没有把所有的方程都用掉,那就肯定没有正常解,下面的行都是全0的
for (int i = line + 1; i <= n; i ++) {
if (abs(mat[i][n + 1]) > esp) {
return -1;// no solution
}
}
return 0;// infinite solution
}
for (int i = 1; i <= n; i ++) {// 用完了就一定是一个对角矩阵
mat[i][n + 1] /= mat[i][i];
mat[i][i] = 1;
}
return 1;// only solution
}
希望能帮助到你!(因为我看到了好多人发帖子但是没人回...