2011-06-16 18:13:29Morris

d766. 11149 - Power of Matrix

內容 :

考慮一個 n * n 矩陣 A :我們確定的Ak = A * A * ... * Ak次)。在這裡,’*’ 表示通常的矩陣乘法。

你要編寫一個程式,計算矩陣A + A2 + A3 + ... + Ak.

Example

 設 A = . 然後 A2 =  = , 因此:

 這樣的計算有多種應用。例如,上面的例子,其實就是下面的路徑圖: 

輸入說明 :

輸入由不超過 20測試資料。每個測試資料第一行包含兩個正整數 n(≤40)和k(≤1000000)。其次是N行,每一個包含N個非負整數,給矩陣 A

輸入是終止條件:n = 0。這種情況下不需要進行處理。

輸出說明 :

對於每個測試資料, 你的程式只要計算A + A2 + A3 + ... + Ak . 算出來的答案可能很大, 你只需要輸出最後一個數字就好. 輸出一行空白列在每筆測試資料後。

 

範例輸入 :

3 20 2 00 0 20 0 00 0

範例輸出 :

0 2 40 0 20 0 0

提示 :

出處 :

11149 - Power of Matrix (管理:asas)



作法 : 數學 & 矩陣乘法 & D&C
A + A2 + A3 + ... + Ak.
if(k&1)/*奇數*/
A + A2 + A3 + ... + Ak = (A + A2 + A3 + ... + Ak/2)*(I + Ak/2 ) + Ak
else
A + A2 + A3 + ... + Ak = (A + A2 + A3 + ... + Ak/2)*(I + Ak/2 )
I : 單位矩陣    k/2 => 取整數
遞迴下去,O(logk)
計算矩陣是O(N^3 logk)

#include<stdio.h>
typedef struct {
    int t[40][40];
}Matrix;
Matrix A, In, init, Ans;
Matrix mult(Matrix x, Matrix  y, int n) {
    Matrix t = init;
    int i, j, k;
    for(i = 0; i < n; i++)
        for(j = 0; j < n; j++)
            for(k = 0; k < n; k++) {
                t.t[i][k] += x.t[i][j]*y.t[j][k];
            }
    for(i = 0; i < n; i++)
        for(j = 0; j < n; j++)
            t.t[i][j] %= 10;
    return t;
}
Matrix add(Matrix x, Matrix  y, int n) {
    int i, j;
    for(i = 0; i < n; i++)
        for(j = 0; j < n; j++)
            x.t[i][j] = (x.t[i][j] + y.t[i][j]) % 10;
    return x;
}
Matrix Calu_Ak(int k, int n) {
    Matrix x = In, y = A;
    while(k) {
        if(k&1) x = mult(x, y, n);
        y = mult(y, y, n);
        k /= 2;
    }
    return x;
}

Matrix Calu_total(int n, int k) {
    if(k == 0) return init;
   
    if(k&1) {
        return add(mult(Calu_total(n, k/2), add(In, Calu_Ak(k/2, n), n), n), Calu_Ak(k, n), n);
    }
    else {
        return mult(Calu_total(n, k/2), add(In, Calu_Ak(k/2, n), n), n);
    }
}
main() {
    int n, a, b, k, x, y, s;
    while(scanf("%d %d", &n, &k) == 2 && n) {
        for(a = 0; a < n; a++)
            for(b = 0; b < n; b++)
                A.t[a][b] = 0, In.t[a][b] = 0,
                init.t[a][b] = 0;
        for(a = 0; a < n; a++) In.t[a][a] = 1;
        for(a = 0; a < n; a++)
            for(b = 0; b < n; b++)
                scanf("%d", &A.t[a][b]), A.t[a][b] %= 10;
        Ans = Calu_total(n, k);
        for(a = 0; a < n; a++, puts(""))
            for(b = 0; b < n; b++) {
                printf("%d", Ans.t[a][b]);
                if(b != n-1)
                    printf(" ");
            }
        puts("");
    }
    return 0;
}