Um algoritmo muito interessante aprendidas em um treinamento qbxt tempo particular.
Pré-conhecimento
- eliminação de Gauss
- euclidiana
problema
Você pode querer pensar sobre o porquê da eliminação Gaussian tradicional haverá problema precisão.
Sabemos que, em quatro operações, apenas um será uma perda de precisão é uma divisão.
Então, quais são a eliminação de Gauss na etapa de divisão usa?
mat[i][i...n+1] /= mat[i][i]
: coeficientes de PCA em 1mat[j=i+1...n][k=i...n+1] -= mat[j][i] * mat[i][k]
: Shomoto
métodos de otimização tradicionais
PCA coluna
O método tradicional é o de seleccionar directamente mat[i][i]
como o elemento principal do coeficiente actual. método principal elemento foi optimizado neste um passo adicional: Nós mat[i...n][i]
escolher um valor máximo absoluto do coeficiente como o principal componente no.
O novo método
Primeiras notas que os "principais componentes fator em 1" não é realmente necessário, só precisa mudar a eliminação equação mat[j=i+1...n][k=i...n+1] -= (mat[j][i] / mat[i][j]) * mat[i][k]
e substituição de volta na final /mat[i][i]
lata.
A questão restante é a eliminação deste passo.
A eliminação utilizando euclidiana
Exemplos de uma divisão euclidiana:
Regras: dois inteiros positivos a partir do original em um número inteiro positivo e um 0 .
Lembre-se que a eliminação subtração eliminação método dos elementos Gaussian desta etapa, o nosso objectivo não é mat[j][i]
tornar-se nula isso?
algoritmo
Cada eliminação, podemos mat[i][i]
e mat[j][i]
dois números separados removido, quando subtraindo dois números, mas estes dois números, onde a linha é também correspondentemente subtraídos.
Após esta operação, mat[i][i]
e mat[j][i]
certamente haverá um torna-se 0 e o outro não é zero. Se mat[i][i]
as mudanças a 0, em seguida, extrair o i-ésimo e linha-th j troca de linha.
Um outro processo de eliminação nota podem ser números negativos.
Código de referência
Apenas para fins de referência , e não se determinou que várias soluções sem solução de
#include <cstdio>
#define ll long long
#define re register
#define il inline
#define gc getchar
#define pc putchar
template <class T>
void read(T &x) {
re bool f = 0;
re char c = gc();
while ((c < '0' || c > '9') && c != '-') c = gc();
if (c == '-') f = 1, c = gc();
x = 0;
while (c >= '0' && c <= '9') x = x * 10 + (c ^ 48), c = gc();
f && (x = -x);
}
template <class T>
void print(T x) {
if (x < 0) pc('-'), x = -x;
if (x >= 10) print(x / 10);
pc((x % 10) ^ 48);
}
template <class T>
void prisp(T x) {
print(x);
pc(' ');
}
template <class T>
void priln(T x) {
print(x);
pc('\n');
}
int n;
int mat[105][105];
void swap(int &a, int &b) {
a ^= b ^= a ^= b;
}
void swp(int* a, int* b) {
for (int i = 1; i <= n + 1; ++i)
swap(a[i], b[i]);
}
void mul(int* a, int t) {
for (int i = 1; i <= n + 1; ++i)
a[i] *= t;
}
void sub(int* a, int* b, int t) {
for (int i = 1; i <= n + 1; ++i)
a[i] -= b[i] * t;
}
int ans[105];
int main() {
read(n);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n + 1; ++j)
read(mat[i][j]);
for (int k = 1; k <= n; ++k) {
// 找主元
for (int i = k; i <= n; ++i) {
if (mat[i][k]) {
if (i != k) swp(mat[i], mat[k]);
break;
}
}
for (int i = k + 1; i <= n; ++i) {
int* a = mat[k];
int* b = mat[i];
// 先化成正数
if (a[k] < 0) mul(a, -1);
if (b[k] < 0) mul(b, -1);
// 辗转相除(迭代版)
while (a[k]) {
if (a[k] > b[k]) {
swp(a, b);
}
sub(b, a, b[k] / a[k]);
swp(a, b);
}
swp(a, b);
}
}
for (int i = n; i >= 1; --i) {
ans[i] = mat[i][n + 1];
for (int j = i + 1; j <= n; ++j)
ans[i] -= ans[j] * mat[i][j];
ans[i] /= mat[i][i];
}
for (int i = 1; i <= n; ++i) priln(ans[i]);
}