高斯消元题二道

  |  

高斯消元模板1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/*
*功能: 列选主元消元法
*@Author: Stephencurry6666
*@Language: C++
*@File Name: gaosixiaoyuan.cpp
*/
/*
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5;

//输出矩阵
void printM(double a[][maxn], int n)
{
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n + 1; j++)
{
printf("%10f,", a[i][j]);
printf("\n");
}
}
}
//选择列主元并进行消元
void SelectColE(double a[][maxn], int n)
{
double temp; //用于记录消元时的因数
for (int i = 1; i <= n; i++)
{
int r = i;
for (int j = i + 1; j <= n; j++)
{
if (fabs(a[j][i]) > fabs(a[r][i]))
r = j;
}
if (r != i)
for (int j = i; j <= n + 1; j++)
swap(a[i][j], a[r][j]); //与最大主元所在行交换
for (int j = i + 1; j <= n; j++)
{ //消元
temp = a[j][i] / a[i][i];
for (int k = i; k <= n + 1; k++)
a[j][k] -= a[i][k] * temp;
}
printf("第%d列消元后:\n", i);
printM(a, 3);
}
}
//高斯消元法(列选主元)
void Gauss(double a[][maxn], int n)
{
SelectColE(a, n); //列选主元并消元成上三角
printf("上三角的结果:\n");
printM(a, 3);
for (int i = n; i >= 1; i--)
{ //回代求解
for (int j = i + 1; j <= n; j++)
a[i][n + 1] -= a[i][j] * a[j][n + 1];
a[i][n + 1] /= a[i][i];
}
}
//测试函数
int main()
{
double a[4][maxn] = {
{0, 0, 0, 0, 0},
{0, 2, 1, -1, 8},
{0, -3, -1, 2, -11},
{0, -2, 1, 2, -3}};
Gauss(a, 3);
for (int i = 1; i <= 3; i++)
printf("X%d = %9f\n", i, a[i][4]);
return 0;
}
*/

高斯消元模板2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/* 用于求整数解得方程组. */
/*
#include <bits/stdc++.h>
using namespace std;

const int maxn = 105;

int equ, var; // 有equ个方程,var个变元。增广阵行数为equ, 分别为0到equ - 1,列数为var + 1,分别为0到var.
int a[maxn][maxn];
int x[maxn]; // 解集.
bool free_x[maxn]; // 判断是否是不确定的变元.
int free_num;

void Debug(void)
{
int i, j;
for (i = 0; i < equ; i++)
{
for (j = 0; j < var + 1; j++)
{
cout << a[i][j] << " ";
}
cout << endl;
}
cout << endl;
}

inline int gcd(int a, int b)
{
int t;
while (b != 0)
{
t = b;
b = a % b;
a = t;
}
return a;
}

inline int lcm(int a, int b)
{
return a * b / gcd(a, b);
}

// 高斯消元法解方程组(Gauss-Jordan elimination).(-2表示有浮点数解,但无整数解,-1表示无解,0表示唯一解,大于0表示无穷解,并返回自由变元的个数)
int Gauss(void)
{
int i, j, k;
int max_r; // 当前这列绝对值最大的行.
int col; // 当前处理的列.
int ta, tb;
int LCM;
int temp;
int free_x_num;
int free_index;
// 转换为阶梯阵.
col = 0; // 当前处理的列.
for (k = 0; k < equ && col < var; k++, col++)
{ // 枚举当前处理的行.
// 找到该col列元素绝对值最大的那行与第k行交换.(为了在除法时减小误差)
max_r = k;
for (i = k + 1; i < equ; i++)
{
if (abs(a[i][col]) > abs(a[max_r][col]))
max_r = i;
}
if (max_r != k)
{ // 与第k行交换.
for (j = k; j < var + 1; j++)
swap(a[k][j], a[max_r][j]);
}
if (a[k][col] == 0)
{ // 说明该col列第k行以下全是0了,则处理当前行的下一列.
k--;
continue;
}
for (i = k + 1; i < equ; i++)
{ // 枚举要删去的行.
if (a[i][col] != 0)
{
LCM = lcm(abs(a[i][col]), abs(a[k][col]));
ta = LCM / abs(a[i][col]), tb = LCM / abs(a[k][col]);
if (a[i][col] * a[k][col] < 0)
tb = -tb; // 异号的情况是两个数相加.
for (j = col; j < var + 1; j++)
{
a[i][j] = a[i][j] * ta - a[k][j] * tb;
}
}
}
}
Debug();
// 1. 无解的情况: 化简的增广阵中存在(0, 0, ..., a)这样的行(a != 0).
for (i = k; i < equ; i++)
{ // 对于无穷解来说,如果要判断哪些是自由变元,那么初等行变换中的交换就会影响,则要记录交换.
if (a[i][col] != 0)
return -1;
}
// 2. 无穷解的情况: 在var * (var + 1)的增广阵中出现(0, 0, ..., 0)这样的行,即说明没有形成严格的上三角阵.
// 且出现的行数即为自由变元的个数.
if (k < var)
{
// 首先,自由变元有var - k个,即不确定的变元至少有var - k个.
for (i = k - 1; i >= 0; i--)
{
// 第i行一定不会是(0, 0, ..., 0)的情况,因为这样的行是在第k行到第equ行.
// 同样,第i行一定不会是(0, 0, ..., a), a != 0的情况,这样的无解的.
free_x_num = 0; // 用于判断该行中的不确定的变元的个数,如果超过1个,则无法求解,它们仍然为不确定的变元.
for (j = 0; j < var; j++)
{
if (a[i][j] != 0 && free_x[j])
free_x_num++, free_index = j;
}
if (free_x_num > 1)
continue; // 无法求解出确定的变元.
// 说明就只有一个不确定的变元free_index,那么可以求解出该变元,且该变元是确定的.
temp = a[i][var];
for (j = 0; j < var; j++)
{
if (a[i][j] != 0 && j != free_index)
temp -= a[i][j] * x[j];
}
x[free_index] = temp / a[i][free_index]; // 求出该变元.
free_x[free_index] = 0; // 该变元是确定的.
}
return var - k; // 自由变元有var - k个.
}
// 3. 唯一解的情况: 在var * (var + 1)的增广阵中形成严格的上三角阵.
// 计算出Xn-1, Xn-2 ... X0.
for (i = var - 1; i >= 0; i--)
{
temp = a[i][var];
for (j = i + 1; j < var; j++)
{
if (a[i][j] != 0)
temp -= a[i][j] * x[j];
}
if (temp % a[i][i] != 0)
return -2; // 说明有浮点数解,但无整数解.
x[i] = temp / a[i][i];
}
return 0;
}

int main(void)
{
freopen("Input.txt", "r", stdin);
int i, j;
while (scanf("%d %d", &equ, &var) != EOF)
{
memset(a, 0, sizeof(a));
memset(x, 0, sizeof(x));
memset(free_x, 1, sizeof(free_x)); // 一开始全是不确定的变元.
for (i = 0; i < equ; i++)
{
for (j = 0; j < var + 1; j++)
{
scanf("%d", &a[i][j]);
}
}
// Debug();
free_num = Gauss();
if (free_num == -1)
printf("无解!\n");
else if (free_num == -2)
printf("有浮点数解,无整数解!\n");
else if (free_num > 0)
{
printf("无穷多解! 自由变元个数为%d\n", free_num);
for (i = 0; i < var; i++)
{
if (free_x[i])
printf("x%d 是不确定的\n", i + 1);
else
printf("x%d: %d\n", i + 1, x[i]);
}
}
else
{
for (i = 0; i < var; i++)
{
printf("x%d: %d\n", i + 1, x[i]);
}
}
printf("\n");
}
return 0;
}

异或方程组的高斯消元

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
//有equ个方程,var个变元。增广矩阵行数为equ,列数为var+1,分别为0到var
int equ,var;
int a[MAXN][MAXN]; //增广矩阵
int x[MAXN]; //解集
int free_x[MAXN];//用来存储自由变元(多解枚举自由变元可以使用)
int free_num;//自由变元的个数

//返回值为-1表示无解,为0是唯一解,否则返回自由变元个数
int Gauss()
{
int max_r,col,k;
free_num = 0;
for(k = 0, col = 0 ; k < equ && col < var ; k++, col++)
{
max_r = k;
for(int i = k+1;i < equ;i++)
{
if(abs(a[i][col]) > abs(a[max_r][col]))
max_r = i;
}
if(a[max_r][col] == 0)
{
k--;
free_x[free_num++] = col;//这个是自由变元
continue;
}
if(max_r != k)
{
for(int j = col; j < var+1; j++)
swap(a[k][j],a[max_r][j]);
}
for(int i = k+1;i < equ;i++)
{
if(a[i][col] != 0)
{
for(int j = col;j < var+1;j++)
a[i][j] ^= a[k][j];
}
}
}
for(int i = k;i < equ;i++)//进入此循环的条件:本身矩阵行大于列 或者 因为出现自由变元后使得非自由变元数比行数小
if(a[i][col] != 0)//若等号右边是1则无解,因为等号左边已经消为0
return -1;//无解
if(k < var) return var-k;//自由变元个数
//唯一解,回代
for(int i = var-1; i >= 0;i--)
{
x[i] = a[i][var];
for(int j = i+1;j < var;j++)
x[i] ^= (a[i][j] && x[j]);
}
return 0;
}

POJ-1222

有一个 5 * 6 的初始矩阵, 1 表示一个亮灯泡, 0 表示一个不亮的灯泡. 对 (i, j) 位置进行一次操作则 (i, j),(i + 1, j), (i - 1, j), (i, j - 1), (i, j + 1) 位置的灯泡变为原来的相反状态, 输出一种能让所有灯泡都变成不亮状态的操作集合.

思路:这道题的话,可以用高斯消元来做。

AC代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
const int MAXN = 3e2;
int equ = 30, var = 30; //有equ个方程,var个变元,增广矩正行数为equ,列数为var+1,从0开始计数
int a[MAXN][MAXN]; //增广矩正
int free_x[MAXN]; //用来存储自由变元(多解枚举自由变元可以使用)
int free_num; //自由变元个数
int x[MAXN]; //解集
int Gauss(void)
{ //返回-1表示无解,0表示有唯一解,否则返回自由变元个数
int max_r, col, k;
free_num = 0;
for (k = 0, col = 0; k < equ && col < var; k++, col++)
{
max_r = k;
for (int i = k + 1; i < equ; i++)
{
if (abs(a[i][col] > abs(a[max_r][col])))
max_r = i;
}
if (a[max_r][col] == 0)
{
k--;
free_x[free_num++] = col; //这个是变元
continue;
}
if (max_r != k)
{
for (int j = col; j < var + 1; j++)
{
swap(a[k][j], a[max_r][j]);
}
}
for (int i = k + 1; i < equ; i++)
{
if (a[i][col] != 0)
{
for (int j = col; j < var + 1; j++)
{
a[i][j] ^= a[k][j];
}
}
}
}
for (int i = k; i < equ; i++)
{
if (a[i][col] != 0)
return -1; //无解
}
if (k < var)
return var - k; //返回自由变元个数
for (int i = var - 1; i >= 0; i--)
{
x[i] = a[i][var];
for (int j = i + 1; j < var; j++)
{
x[i] ^= (a[i][j] && x[j]);
}
}
return 0;
}
int main(void)
{
int t, n;
cin >> t;
for (int cas = 1; cas <= t; cas++)
{
for (int i = 0; i < 30; i++)
{
cin >> a[i][30];
x[i] = 0; //清空数组
}
for (int i = 0; i < 30; i++)
{ //构造增广矩阵
int x1 = i / 6;
int y1 = i % 6;
for (int j = 0; j < 30; j++)
{
int x2 = j / 6;
int y2 = j % 6;
if (abs(x1 - x2) + abs(y1 - y2) < 2)
a[j][i] = 1;
else
a[j][i] = 0;
}
}
Gauss();
cout << "PUZZLE #" << cas << endl;
for (int i = 0; i < 30; i++)
{
cout << x[i] << " ";
if ((i + 1) % 6 == 0)
cout << endl;
}
}
return 0;
}

POJ-1830

题意:中文题,不过多叙述题意。

思路:https://blog.csdn.net/immiao/article/details/17342143

AC代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
int A[35][35];
int B[35];
int n;
int ans;
void swap(int a, int b)
{
int i;
int temp;
for (i = 0; i <= n - 1; i++)
{
temp = A[a][i];
A[a][i] = A[b][i];
A[b][i] = temp;
}
temp = B[a];
B[a] = B[b];
B[b] = temp;
}
void gauss()
{
int i, j, k;
for (i = 0; i <= n - 1; i++)
{
bool flag = false;
if (!A[i][i])
{
for (j = i + 1; j <= n - 1; j++)
{
if (A[j][i])
{
swap(i, j);
flag = true;
break;
}
}
if (!flag)
continue;
}

for (j = i + 1; j <= n - 1; j++)
{
if (A[j][i])
{
for (k = i; k <= n - 1; k++)
A[j][k] ^= A[i][k];
B[j] ^= B[i];
}
}
}
for (i = n - 1; i >= 0; i--)
{
if (A[i][i] == 0 && B[i] == 1)
{
ans = -1;
break;
}
else if (A[i][i] == 0)
ans = ans << 1;
else
{
for (j = i - 1; j >= 0; j--)
{
if (A[j][i])
{
A[j][i] ^= A[i][i];
B[j] ^= B[i];
}
}
}
}
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
ans = 1;
scanf("%d", &n);
int i;

int s[35], e[35];

for (i = 0; i <= n - 1; i++)
scanf("%d", &s[i]);
for (i = 0; i <= n - 1; i++)
{
scanf("%d", &e[i]);
if (e[i] != s[i])
B[i] = 1;
else
B[i] = 0;
}

memset(A, 0, sizeof(A));
for (i = 0; i <= n - 1; i++)
A[i][i] = 1;
while (1)
{
int a, b;
scanf("%d%d", &a, &b);
if (!a && !b)
break;
A[b - 1][a - 1] = 1;
}

gauss();
if (ans != -1)
printf("%d\n", ans);
else
printf("Oh,it's impossible~!!\n");
}
return 0;
}

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. 高斯消元模板1
  2. 2. 高斯消元模板2
  3. 3. 异或方程组的高斯消元
  4. 4. POJ-1222
  5. 5. POJ-1830
,
字数统计:87.6k 载入天数...载入时分秒...