E127. Вычисление определителя методом Краута за O (N3)

e-maxx algorithm original: C/C++ #algorithm #emaxx #linear-algebra #math #matrix
Văn bản bài toán được dịch từ tiếng Nga theo ngôn ngữ giao diện. Mã không thay đổi.

Источник: e-maxx.ru/algo, страница PDF 417.

Здесь будет рассмотрена модификация метода Краута (Crout), позволяющая вычислить определитель матрицы за O (N3).

Собственно Thuật toán Краута находит разложение матрицы A в виде A = L U, где L - нижняя, а U - верхняя треугольная матрицы. Без Ràng buộc общности можно считать, что в L все диагональные elementы равны 1. Но, зная эти матрицы, легко вычислить определитель A: он будет равен произведению всех elementов, стоящих на главной диагонали матрицы U. Имеется теорема, согласно которой любая обратимая матрица обладает LU-разложением, и притом единственным, тогда и только тогда, когда все её главные миноры отличны от нуля. Следует напомнить, что мы рассматриваем только такие разложения, в которых диагональ L состоит только из единиц; иначе же, вообще говоря, разложение не единственно.

Пусть A - матрица, N - её размер. Мы найдём elementы матриц L и U. Сам Thuật toán состоит из следующих шагов:

1. Положим Li i = 1 для i = 1, 2, ..., N

2. Для каждого j = 1, 2, ..., N выполним: 1. Для i = 1, 2, ..., j найдём значение Ui j:

Ui j = Ai j - SUM Li k Uk j ,

где сумма по всем k = 1, 2, ..., i-1. 2. Далее, для i = j+1, j+2, ..., N имеем:

Li j = (Ai j - SUM Li k Uk j) / Uj j ,

где сумма берётся по всем k = 1, 2, ..., j-1.

Cài đặt

Код на Java (с использованием дробной длинной арифметики):

static BigInteger det (BigDecimal a [][], int n)

{

try {

for (int i=0; i<n; i++)

{

boolean nonzero = false;

for (int j=0; j<n; j++)
if (a[i][j].compareTo (new BigDecimal

(BigInteger.ZERO)) > 0)

nonzero = true;

if (!nonzero)
return BigInteger.ZERO;

}

BigDecimal scaling [] = new BigDecimal [n];

for (int i=0; i<n; i++)

{

BigDecimal big = new BigDecimal (BigInteger.ZERO);

for (int j=0; j<n; j++)
if (a[i][j].abs().compareTo (big) > 0)

big = a[i][j].abs();

scaling[i] = (new BigDecimal (BigInteger.ONE)) .divide

(big, 100, BigDecimal.ROUND_HALF_EVEN);

}

int sign = 1;
for (int j=0; j<n; j++)

{

for (int i=0; i<j; i++)

{

BigDecimal sum = a[i][j];

for (int k=0; k<i; k++)

sum = sum.subtract (a[i][k].multiply (a[k][j]));

a[i][j] = sum;

}

BigDecimal big = new BigDecimal (BigInteger.ZERO);

int imax = -1;
for (int i=j; i<n; i++)

{

BigDecimal sum = a[i][j];

for (int k=0; k<j; k++)

sum = sum.subtract (a[i][k].multiply (a[k][j]));

a[i][j] = sum;

BigDecimal cur = sum.abs();

cur = cur.multiply (scaling[i]);

if (cur.compareTo (big) >= 0)

{

big = cur;

imax = i;

} }

if (j != imax)

{

for (int k=0; k<n; k++)

{

BigDecimal t = a[j][k];

a[j][k] = a[imax][k];

a[imax][k] = t;

}

BigDecimal t = scaling[imax];

scaling[imax] = scaling[j];

scaling[j] = t;

sign = -sign;

}

if (j != n-1)
for (int i=j+1; i<n; i++)

a[i][j] = a[i][j].divide

(a[j][j], 100,

BigDecimal.ROUND_HALF_EVEN);

}

BigDecimal result = new BigDecimal (1);

if (sign == -1)

result = result.negate();

for (int i=0; i<n; i++)

result = result.multiply (a[i][i]);

return result.divide

(BigDecimal.valueOf(1), 0, BigDecimal.

ROUND_HALF_EVEN).toBigInteger();

}

catch (Exception e)

{

return BigInteger.ZERO;

} }

C# lời giải

bản nháp tự động, xem lại trước khi gửi
using System;
using System.Collections.Generic;
using System.Linq;

public static class AlgorithmDraft
{
    // Auto-generated C# draft from the original e-maxx C/C++ listing. Review before production use.
    static BigInteger det (BigDecimal a [][], int n)
    {
            try {
            for (int i=0; i<n; i++)
            {
                    boolean nonzero = false;
                    for (int j=0; j<n; j++)
                            if (a[i][j].compareTo (new BigDecimal
    (BigInteger.ZERO)) > 0)
                                    nonzero = true;
                    if (!nonzero)
                            return BigInteger.ZERO;
            }
            BigDecimal scaling [] = new BigDecimal [n];
            for (int i=0; i<n; i++)
            {
                    BigDecimal big = new BigDecimal (BigInteger.ZERO);
                    for (int j=0; j<n; j++)
                            if (a[i][j].abs().compareTo (big) > 0)
                                    big = a[i][j].abs();
                    scaling[i] = (new BigDecimal (BigInteger.ONE)) .divide
                            (big, 100, BigDecimal.ROUND_HALF_EVEN);
            }
            int sign = 1;
            for (int j=0; j<n; j++)
            {
                    for (int i=0; i<j; i++)
                    {
                            BigDecimal sum = a[i][j];
                            for (int k=0; k<i; k++)
                                    sum = sum.subtract (a[i][k].multiply (a[k][j]));
                            a[i][j] = sum;
                    }
                    BigDecimal big = new BigDecimal (BigInteger.ZERO);
                    int imax = -1;
                    for (int i=j; i<n; i++)
                    {
                            BigDecimal sum = a[i][j];
                            for (int k=0; k<j; k++)
                                    sum = sum.subtract (a[i][k].multiply (a[k][j]));
                            a[i][j] = sum;
                            BigDecimal cur = sum.abs();
                            cur = cur.multiply (scaling[i]);
                            if (cur.compareTo (big) >= 0)
                            {
                                    big = cur;
                                    imax = i;
                            }
                    }
                    if (j != imax)
                    {
                            for (int k=0; k<n; k++)
                            {
                                    BigDecimal t = a[j][k];
                                    a[j][k] = a[imax][k];
                                    a[imax][k] = t;
                            }
                            BigDecimal t = scaling[imax];
                            scaling[imax] = scaling[j];
                            scaling[j] = t;
                            sign = -sign;
                    }
                    if (j != n-1)
                            for (int i=j+1; i<n; i++)
                                    a[i][j] = a[i][j].divide
                                            (a[j][j], 100,
    BigDecimal.ROUND_HALF_EVEN);
            }
            BigDecimal result = new BigDecimal (1);
            if (sign == -1)
                    result = result.negate();
            for (int i=0; i<n; i++)
                    result = result.multiply (a[i][i]);
            return result.divide
                    (BigDecimal.valueOf(1), 0, BigDecimal.
    ROUND_HALF_EVEN).toBigInteger();
            }
            catch (Exception e)
            {
                    return BigInteger.ZERO;
            }
    }
}

C++ lời giải

đã khớp/gốc
static BigInteger det (BigDecimal a [][], int n)
{
        try {
        for (int i=0; i<n; i++)
        {
                boolean nonzero = false;
                for (int j=0; j<n; j++)
                        if (a[i][j].compareTo (new BigDecimal
(BigInteger.ZERO)) > 0)
                                nonzero = true;
                if (!nonzero)
                        return BigInteger.ZERO;
        }
        BigDecimal scaling [] = new BigDecimal [n];
        for (int i=0; i<n; i++)
        {
                BigDecimal big = new BigDecimal (BigInteger.ZERO);
                for (int j=0; j<n; j++)
                        if (a[i][j].abs().compareTo (big) > 0)
                                big = a[i][j].abs();
                scaling[i] = (new BigDecimal (BigInteger.ONE)) .divide
                        (big, 100, BigDecimal.ROUND_HALF_EVEN);
        }
        int sign = 1;
        for (int j=0; j<n; j++)
        {
                for (int i=0; i<j; i++)
                {
                        BigDecimal sum = a[i][j];
                        for (int k=0; k<i; k++)
                                sum = sum.subtract (a[i][k].multiply (a[k][j]));
                        a[i][j] = sum;
                }
                BigDecimal big = new BigDecimal (BigInteger.ZERO);
                int imax = -1;
                for (int i=j; i<n; i++)
                {
                        BigDecimal sum = a[i][j];
                        for (int k=0; k<j; k++)
                                sum = sum.subtract (a[i][k].multiply (a[k][j]));
                        a[i][j] = sum;
                        BigDecimal cur = sum.abs();
                        cur = cur.multiply (scaling[i]);
                        if (cur.compareTo (big) >= 0)
                        {
                                big = cur;
                                imax = i;
                        }
                }
                if (j != imax)
                {
                        for (int k=0; k<n; k++)
                        {
                                BigDecimal t = a[j][k];
                                a[j][k] = a[imax][k];
                                a[imax][k] = t;
                        }
                        BigDecimal t = scaling[imax];
                        scaling[imax] = scaling[j];
                        scaling[j] = t;
                        sign = -sign;
                }
                if (j != n-1)
                        for (int i=j+1; i<n; i++)
                                a[i][j] = a[i][j].divide
                                        (a[j][j], 100,
BigDecimal.ROUND_HALF_EVEN);
        }
        BigDecimal result = new BigDecimal (1);
        if (sign == -1)
                result = result.negate();
        for (int i=0; i<n; i++)
                result = result.multiply (a[i][i]);
        return result.divide
                (BigDecimal.valueOf(1), 0, BigDecimal.
ROUND_HALF_EVEN).toBigInteger();
        }
        catch (Exception e)
        {
                return BigInteger.ZERO;
        }
}

Java lời giải

bản nháp tự động, xem lại trước khi gửi
import java.util.*;
import java.math.*;

public class AlgorithmDraft {
    // Auto-generated Java draft from the original e-maxx C/C++ listing. Review before production use.
    static BigInteger det (BigDecimal a [][], int n)
    {
            try {
            for (int i=0; i<n; i++)
            {
                    booleanean nonzero = false;
                    for (int j=0; j<n; j++)
                            if (a[i][j].compareTo (new BigDecimal
    (BigInteger.ZERO)) > 0)
                                    nonzero = true;
                    if (!nonzero)
                            return BigInteger.ZERO;
            }
            BigDecimal scaling [] = new BigDecimal [n];
            for (int i=0; i<n; i++)
            {
                    BigDecimal big = new BigDecimal (BigInteger.ZERO);
                    for (int j=0; j<n; j++)
                            if (a[i][j].abs().compareTo (big) > 0)
                                    big = a[i][j].abs();
                    scaling[i] = (new BigDecimal (BigInteger.ONE)) .divide
                            (big, 100, BigDecimal.ROUND_HALF_EVEN);
            }
            int sign = 1;
            for (int j=0; j<n; j++)
            {
                    for (int i=0; i<j; i++)
                    {
                            BigDecimal sum = a[i][j];
                            for (int k=0; k<i; k++)
                                    sum = sum.subtract (a[i][k].multiply (a[k][j]));
                            a[i][j] = sum;
                    }
                    BigDecimal big = new BigDecimal (BigInteger.ZERO);
                    int imax = -1;
                    for (int i=j; i<n; i++)
                    {
                            BigDecimal sum = a[i][j];
                            for (int k=0; k<j; k++)
                                    sum = sum.subtract (a[i][k].multiply (a[k][j]));
                            a[i][j] = sum;
                            BigDecimal cur = sum.abs();
                            cur = cur.multiply (scaling[i]);
                            if (cur.compareTo (big) >= 0)
                            {
                                    big = cur;
                                    imax = i;
                            }
                    }
                    if (j != imax)
                    {
                            for (int k=0; k<n; k++)
                            {
                                    BigDecimal t = a[j][k];
                                    a[j][k] = a[imax][k];
                                    a[imax][k] = t;
                            }
                            BigDecimal t = scaling[imax];
                            scaling[imax] = scaling[j];
                            scaling[j] = t;
                            sign = -sign;
                    }
                    if (j != n-1)
                            for (int i=j+1; i<n; i++)
                                    a[i][j] = a[i][j].divide
                                            (a[j][j], 100,
    BigDecimal.ROUND_HALF_EVEN);
            }
            BigDecimal result = new BigDecimal (1);
            if (sign == -1)
                    result = result.negate();
            for (int i=0; i<n; i++)
                    result = result.multiply (a[i][i]);
            return result.divide
                    (BigDecimal.valueOf(1), 0, BigDecimal.
    ROUND_HALF_EVEN).toBigInteger();
            }
            catch (Exception e)
            {
                    return BigInteger.ZERO;
            }
    }
}

Материал разбит как Thuật toánическая Bài toán: изучить постановку, понять асимптотику и реализовать Thuật toán на выбранном языке.

Vacancies for this task

việc làm đang hoạt động with overlapping task tags are đã hiển thị.

Tất cả việc làm
Chưa có việc làm đang hoạt động.