using System;
using System.Diagnostics;
using System.Threading.Tasks;

class Program
{
    static void SequentialDeterminantCalculation(int matrixSize, int lowerLimit, int upperLimit)
    {
        int[][] randomMatrix = GenerateRandomMatrix(matrixSize, lowerLimit, upperLimit);

        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
        int result = Determinant(randomMatrix);
        stopwatch.Stop();
        TimeSpan elapsedTime = stopwatch.Elapsed;
        Console.WriteLine($"Последовательный детерминант: {result}");
        Console.WriteLine($"Последовательное время: {elapsedTime.TotalSeconds:F7} секунд");
    }

    static void ParallelDeterminantCalculation(int matrixSize, int lowerLimit, int upperLimit, int numProcesses)
    {
        int[][] randomMatrix = GenerateRandomMatrix(matrixSize, lowerLimit, upperLimit);

        int[][] matricesToProcess = new int[matrixSize][];
        for (int col = 0; col < matrixSize; col++)
        {
            matricesToProcess[col] = Submatrix(randomMatrix, 0, col)[0];
        }

        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
        int[] determinants = new int[matrixSize];
        Parallel.For(0, matrixSize, new ParallelOptions { MaxDegreeOfParallelism = numProcesses }, col =>
        {
            determinants[col] = Determinant(new int[][] { matricesToProcess[col] });
        });

        int result = 0;
        for (int col = 0; col < matrixSize; col++)
        {
            result += ((-1) * col) * randomMatrix[0][col] * determinants[col];
        }
        stopwatch.Stop();
        TimeSpan elapsedTime = stopwatch.Elapsed;
        Console.WriteLine($"Параллельный детерминант: {result}");
        Console.WriteLine($"Параллельное время: {elapsedTime.TotalSeconds:F7} секунд");
    }

    static int[][] GenerateRandomMatrix(int matrixSize, int lowerLimit, int upperLimit)
    {
        Random random = new Random();
        int[][] matrix = new int[matrixSize][];

        for (int i = 0; i < matrixSize; i++)
        {
            matrix[i] = new int[matrixSize];
            for (int j = 0; j < matrixSize; j++)
            {
                matrix[i][j] = random.Next(lowerLimit, upperLimit);
            }
        }

        return matrix;
    }

    static int[][] Submatrix(int[][] matrix, int rowToDelete, int colToDelete)
    {
        int size = matrix.Length - 1;
        int[][] submatrix = new int[size][];

        int rowIndex = 0;

        for (int i = 0; i < matrix.Length; i++)
        {
            if (i == rowToDelete)
                continue;

            submatrix[rowIndex] = new int[size];

            int colIndex = 0;
            for (int j = 0; j < matrix.Length; j++)
            {
                if (j == colToDelete)
                    continue;

                submatrix[rowIndex][colIndex] = matrix[i][j];
                colIndex++;
            }

            rowIndex++;
        }

        return submatrix;
    }

    static int Determinant(int[][] matrix)
    {
        int n = matrix.Length;
        if (n == 1)
        {
            return matrix[0][0];
        }
        else if (n == 2)
        {
            return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
        }
        else
        {
            int determinant = 0;

            for (int j = 0; j < n; j++)
            {
                int[][] submatrix = Submatrix(matrix, 0, j);
                int subDeterminant = Determinant(submatrix);
                determinant += ((-1) * j) * matrix[0][j] * subDeterminant;
            }

            return determinant;
        }
    }

    static void Main(string[] args)
    {
        SequentialDeterminantCalculation(10, 0, 10);
        Console.WriteLine();

        int[] numThreads = { 1, 2, 4, 6, 8, 12, 16, 32 };

        for (int i = 0; i < 8; i++)
        {
            Console.WriteLine($"Количество потоков: {numThreads[i]}");
            ParallelDeterminantCalculation(10, 0, 10, numThreads[i]);
        }
    }
}
