LINUX.ORG.RU

Помогите найти баг в алгоритме


0

1

Надо возвести матрицу 2на2 в степень и при этом оставлять только остатки от деления на m/mod что бы в регистре умещались числа.

Но, бида бида, если ввести

 
500 499 
499 498 
123456789 1000 
получится 

321 80
80 481

вместо правильных

792 815
815 422

Куда копать?

#include<iostream>
#include<vector>
using namespace std;



typedef vector< vector<int> > Matrix;

Matrix mult(Matrix M1, Matrix M2, const int mod) {
    Matrix M(2,vector<int>(2, 0));
    for (int i = 0; i < 2; ++i) {
        for (int j = 0; j < 2; ++j) {
            for (int k = 0; k < 2; ++k) {
                M[i][j] += M1[i][k]*M2[k][j];
            }
            M[i][j] %= mod;

        }

    }
    /*
    M[0][0] = (M1[0][0]*M2[0][0] + M1[1][0]*M2[0][1])%mod;
    M[0][1] = (M1[0][1]*M2[0][0] + M1[1][1]*M2[0][1])%mod;
    M[1][0] = (M1[0][0]*M2[1][0] + M1[1][0]*M2[1][1])%mod;
    M[1][1] = (M1[0][1]*M2[1][0] + M1[1][1]*M2[1][1])%mod;*/
    /* cout << M[0][0] << ' ' << M[0][1] << endl
        <<  M[1][0] << ' ' << M[1][1] << endl
        <<  "----------" << endl;*/
    return M;
}

Matrix pow(Matrix M, int n, const int mod) {
    if (n > 1) {
        if(n%2 == 1) M = mult(mult(M, M, mod), M, mod);
        else M = mult(M, M, mod);

        return pow(M, n/2, mod);
    }
    else if (n == 0) {
        M[0][0] = 1;
        M[0][1] = 0;
        M[1][0] = 0;
        M[1][1] = 1;
    }
    return M;
}

int main() {
    Matrix M(2,vector<int>(2));
    int n, m;
    while (cin >> M[0][0] >> M[0][1] >> M[1][0] >> M[1][1] >> n >> m) {
        M = pow(M, n, m);
        cout << M[0][0] << ' ' << M[0][1] << endl
            <<  M[1][0] << ' ' << M[1][1] << endl
            <<  "----------" << endl;
    }
}

Перемещено annoynimous из talks

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

Если поменять их местами на больших матрицах можно много профита получить, раз эдак в 10-20 быстрее считаться будет.

Dantix ★★
()
if(n%2 == 1) M = mult(mult(M, M, mod), M, mod);
        else M = mult(M, M, mod);

        return pow(M, n/2, mod);

Если n = 2k+1, то надо считать (M^2)^k*M, а ты считаешь (M^3)^k

PS: а другую букавку, отличную от M, для промежуточных результатов завести никак?

ival ★★
()
Ответ на: комментарий от qnikst

Мне кажется такие задачки проще понять с рекурсией. Потом можно уже переводить на итерации.

Trieforce
() автор топика

Как любезно подсказывает ival, в коде рекурсии ошибка.
Надо так:

if (n > 1) {
if(n%2 == 1)
M = mult(M, pow(M, n-1, mod), mod);
else
M = pow(mult(M, M, mod), n/2, mod);
}

и тогда получается желанный ответ

ringill
()

Надо возвести матрицу 2на2 в степень

Вам наверное про дебагер ничего не рассказывали? Тут минут за 10-20 можно дебагером пройтись вдоль и в поперек.

ymuv ★★★★
()

Пользуясь нехитрыми правилами
(a + b) % c == (a % c + b % c) % c
(a * b) % c == ((a % c) * (b % c)) % c
Можно избежать переполнения чисел
Те писать
M[j] += (M[k] % mod) * (M[k][j] % mod) % mod

bga_ ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.