#include <stdio.h>
#include <stdlib.h>

#define MAX_SIZE 100

// Прототипы функций
int **allocate_matrix_dynamic(int rows, int cols);
void free_matrix_dynamic(int **matrix, int rows);
void read_matrix(int **matrix, int rows, int cols);
void print_matrix(int **matrix, int rows, int cols);
void add_matrices(int **A, int **B, int **C, int rows, int cols);
void multiply_matrices(int **A, int **B, int **C, int rowsA, int colsA, int colsB);
void transpose_matrix(int **A, int **B, int rows, int cols);

int main() {
    int operation;
    printf("Выберите операцию:\\n1 - Сложение матриц\\n2 - Умножение матриц\\n3 - Транспонирование матрицы\\n");
    if (scanf("%d", &operation) != 1 || operation < 1 || operation > 3) {
        printf("n/a\\n");
        return 1; // Ошибка выбора
    }

    if (operation == 1) {
        // Сложение матриц
        int rows, cols;
        if (scanf("%d %d", &rows, &cols) != 2 || rows < 1 || cols < 1 || rows > MAX_SIZE || cols > MAX_SIZE) {
            printf("n/a\\n");
            return 1; // Ошибка при считывании размеров матриц
        }

        int **A = allocate_matrix_dynamic(rows, cols);
        int **B = allocate_matrix_dynamic(rows, cols);
        int **C = allocate_matrix_dynamic(rows, cols);
        
        if (A == NULL || B == NULL || C == NULL) {
            printf("n/a\\n");
            return 1; // Ошибка при выделении памяти
        }

        read_matrix(A, rows, cols);
        read_matrix(B, rows, cols);
        add_matrices(A, B, C, rows, cols);
        print_matrix(C, rows, cols);
        
        free_matrix_dynamic(A, rows);
        free_matrix_dynamic(B, rows);
        free_matrix_dynamic(C, rows);
    } else if (operation == 2) {
        // Умножение матриц
        int rowsA, colsA, rowsB, colsB;
        if (scanf("%d %d", &rowsA, &colsA) != 2 || rowsA < 1 || colsA < 1 || rowsA > MAX_SIZE || colsA > MAX_SIZE) {
            printf("n/a\\n");
            return 1; // Ошибка при считывании размеров первой матрицы
        }
        
        if (scanf("%d %d", &rowsB, &colsB) != 2 || rowsB < 1 || colsB < 1 || rowsB > MAX_SIZE || colsB > MAX_SIZE) {
            printf("n/a\\n");
            return 1; // Ошибка при считывании размеров второй матрицы
        }
        
        if (colsA != rowsB) {
            printf("n/a\\n");
            return 1; // Ошибка, если количество столбцов первой матрицы не совпадает с количеством строк второй
        }

        int **A = allocate_matrix_dynamic(rowsA, colsA);
        int **B = allocate_matrix_dynamic(rowsB, colsB);
        int **C = allocate_matrix_dynamic(rowsA, colsB);
        
        if (A == NULL || B == NULL || C == NULL) {
            printf("n/a\\n");
            return 1; // Ошибка при выделении памяти
        }

        read_matrix(A, rowsA, colsA);
        read_matrix(B, rowsB, colsB);
        multiply_matrices(A, B, C, rowsA, colsA, colsB);
        print_matrix(C, rowsA, colsB);
        
        free_matrix_dynamic(A, rowsA);
        free_matrix_dynamic(B, rowsB);
        free_matrix_dynamic(C, rowsA);
    } else if (operation == 3) {
        // Транспонирование матрицы
        int rows, cols;
        if (scanf("%d %d", &rows, &cols) != 2 || rows < 1 || cols < 1 || rows > MAX_SIZE || cols > MAX_SIZE) {
            printf("n/a\\n");
            return 1; // Ошибка при считывании размеров матрицы
        }

        int **A = allocate_matrix_dynamic(rows, cols);
        int **B = allocate_matrix_dynamic(cols, rows); // Транспонированная матрица

        if (A == NULL || B == NULL) {
            printf("n/a\\n");
            return 1; // Ошибка при выделении памяти
        }

        read_matrix(A, rows, cols);
        transpose_matrix(A, B, rows, cols);
        print_matrix(B, cols, rows);
        
        free_matrix_dynamic(A, rows);
        free_matrix_dynamic(B, cols);
    }

    return 0;
}

// Динамическое выделение: 2D массив
int **allocate_matrix_dynamic(int rows, int cols) {
    int **matrix = malloc(rows * sizeof(int *));
    if (matrix == NULL) return NULL;

    for (int i = 0; i < rows; i++) {
        matrix[i] = malloc(cols * sizeof(int));
        if (matrix[i] == NULL) {
            for (int j = 0; j < i; j++) {
                free(matrix[j]);
            }
            free(matrix);
            return NULL;
        }
    }
    return matrix;
}

// Освобождение памяти для динамической матрицы
void free_matrix_dynamic(int **matrix, int rows) {
    for (int i = 0; i < rows; i++) {
        free(matrix[i]);
    }
    free(matrix);
}

// Чтение матрицы
void read_matrix(int **matrix, int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            if (scanf("%d", &matrix[i][j]) != 1) {
                printf("n/a\\n");
                exit(1); // Ошибка при считывании
            }
        }
    }
}

// Печать матрицы
void print_matrix(int **matrix, int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            printf("%d", matrix[i][j]);
            if (j < cols - 1) {
                printf(" ");
            }
        }
        if (i < rows - 1) {
            printf("\\n");
        }
    }
}

// Сложение матриц
void add_matrices(int **A, int **B, int **C, int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            C[i][j] = A[i][j] + B[i][j];
        }
    }
}

// Умножение матриц
void multiply_matrices(int **A, int **B, int **C, int rowsA, int colsA, int colsB) {
    for (int i = 0; i < rowsA; i++) {
        for (int j = 0; j < colsB; j++) {
            C[i][j] = 0; // Инициализация элемента C
            for (int k = 0; k < colsA; k++) {
                C[i][j] += A[i][k] * B[k][j];
            }
        }
    }
}

// Транспонирование матрицы
void transpose_matrix(int **A, int **B, int rows, int cols) {
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
            B[j][i] = A[i][j];
        }
    }
}