注意事项:
最好先理解经典高斯消元再来看这道题:java—高斯消元—线性方程组
题目:
输入:
3
1 1 0 1
0 1 1 0
1 0 0 1
输出:
1
0
0
public class 高斯消元解异或线性方程组 {
//m表示总共有几个式子,每个式子中的有m+1个元素
public static int N = 110, m;
public static int[][] a = new int[N][N];
public static void main(String[] args) {
//将式子读入到a中
Scanner in = new Scanner(System.in);
m = in.nextInt();
for (int i = 0; i<m; i++) {
for (int j = 0; j<m+1; j++) {
a[i][j] = in.nextInt();
}
}
//接收gauss结果,0代表有唯一解,1代表多种解,2代表无解
int res = gauss();
if (res == 0) {
for (int i = 0; i<m; i++) System.out.println(a[i][m]);
}
else if (res == 1) System.out.println("Multiple sets of solutions");
else if (res == 2) System.out.println("No solution");
}
//这里整个还是经典gauss的思路
public static int gauss() {
//c是column列,r是row行, 每次遍历从r开始的c列中的所有值,拿到c列中第一个1出现的位置t行
int r, c;
for (r = c = 0; c<m; c++) {
int t = r;
for (int i = r; i<m; i++) {
if (a[i][c] == 1) {
t = i;
break;
}
}
if (a[t][c] == 0) continue; //如果为0,那么就说明当前列全部为0,直接跳到下一列
for (int i = c; i<m+1; i++) swap(a[r], a[t], i); //将a[t]列和a[r]列进行交换,也就是将t行和当前最顶端r行进行交换
for (int i = r+1; i<m; i++) { //从第r行开始,将第c列的所有数都消为0
if (a[i][c] != 0) {
for (int j = m; j>=c; j--) {
//位运算,将本行的所有元素都&行首,这样就能保证,行首 ^= (1 & 行首) = 0
//位运算符^是相同为1,不同为0
//位运算符&是同时为1就是1,其余情况为0
a[i][j] ^= a[i][c] & a[r][j];
}
}
}
r++; //正常循环,跳到下一行
}
//r小于m说明剩下的方程个数小于m,不存在唯一解,判断是无解还是有无数组解
if (r < m) {
for (int i = r; i<m; i++) {
if (a[i][m] != 0) return 2; //也就是如果0等于非0的情况,无解
}
return 1; //有多数组解
}
//如果有唯一解,那么倒着消一遍就可以了,也就是从倒数第二行开始,将等式左边从1开始的非0数,根据下一行对应列的值进行消元,直到等式左侧除了那个1以外所有值为0
for (int i = m-1; i>=0; i--) {
for (int j = i+1; j<m; j++) {
a[i][m] ^= a[i][j] & a[j][m];
}
}
return 0;
}
//我已经无力吐槽java的swap了
public static void swap(int[] a, int[] b, int c) {
int temp = a[c];
a[c] = b[c];
b[c] = temp;
}
}
思路:
本质上和经典高斯消元一样:
1.遍历每一列
2.从当前最顶端r行开始,找到非0列c所在的行t
3.将t行和r行进行交换位置
4.用最顶端的行对c列中的值进行消0操作
注意一点就是,经典高斯消元中有一步是通过将本行所有元素除行首,使得本行的行首消为1,异或线性方程组不需要这一步,因为我们找到非0列c的时候,其实就是找到了1,因为只有0和1两种元素