警钟撅烂——如果你约旦并且不会区分无解/无数解
查看原帖
警钟撅烂——如果你约旦并且不会区分无解/无数解
1033727
toolazy楼主2023/11/17 23:38

题解讲的都不清晰,甚至有点问题。

实际上,使用高斯——约旦消元法也是可以区分的。按照正常的流程处理,但当你发现没有可以替换的方程(所有的下面的方程都是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
}

希望能帮助到你!(因为我看到了好多人发帖子但是没人回...

2023/11/17 23:38
加载中...