Black Technology: Gaussian Elimination how to improve the speed and accuracy of integer art - Gaussian elimination phase was removed and the division binding

A very interesting algorithm learned at a particular time qbxt training.

Pre-knowledge

  • Gaussian elimination
  • Euclidean

problem

You may wish to think about why the traditional Gaussian elimination there will be accuracy problem.

We know that in four operations, only one will be a loss of precision is a division.

So what are the Gaussian elimination in the division step uses it?

  1. mat[i][i...n+1] /= mat[i][i]: PCA coefficients into 1
  2. mat[j=i+1...n][k=i...n+1] -= mat[j][i] * mat[i][k]: Shomoto

Traditional optimization methods

Column PCA

The traditional method is to directly select mat[i][i]as the main element of the current coefficient. Main-element method has been optimized in this a step further: We mat[i...n][i]choose a maximum absolute value of the coefficient as the principal component in.

The new method

First notes that the "principal components factor into 1" is actually not necessary, just need to change the equation elimination mat[j=i+1...n][k=i...n+1] -= (mat[j][i] / mat[i][j]) * mat[i][k]and back substitution in the final /mat[i][i]can.

The remaining question is the elimination of this step.

Elimination using Euclidean

Examples of a Euclidean division:

\[(155,120)=(35,120)=(35,15)=(5,15)=(5,0) \]

Rules: two positive integers from the original into a positive integer and a 0 .

Recall that the Gaussian elimination subtraction element method elimination of this step, our aim is to not mat[j][i]become zero it?

algorithm

Each elimination, we can mat[i][i]and mat[j][i]two numbers divided removed, when subtracting two numbers, but these two numbers where the row is also correspondingly subtracted.

After this operation, mat[i][i]and mat[j][i]there will certainly be a becomes 0 and the other is not zero. If mat[i][i]changes to 0, then draw the i-th row and j-th row exchange.

Another note elimination process may be negative numbers.

Reference Code

For reference purposes only , and is not determined that multiple solutions without solution of

#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]);
}

Guess you like

Origin www.cnblogs.com/water-lift/p/12606267.html