學習之旅——矩陣快速冪總結

基礎知識:(會基礎的直接看應用部分)

(1)矩陣乘法

簡單的說矩陣就是二維數組,數存在裏面,矩陣乘法的規則:A*B=C

其中c[i][j]爲A的第i行與B的第j列對應乘積的和,即:

代碼:

 


 
  1. const int N=100;

  2. int c[N][N];

  3. void multi(int a[][N],int b[][N],int n)//n是矩陣大小,n<N

  4. {

  5. memset(c,0,sizeof c);

  6. for(int i=1;i<=n;i++)

  7. for(int j=1;j<=n;j++)

  8. for(int k=1;k<=n;k++)

  9. c[i][j]+=a[i][k]*b[k][j];

  10. }


另一種寫法:

 

 


 
  1. int c[N][N];

  2. void multi(int a[][N],int b[][N],int n)

  3. {

  4. memset(c,0,sizeof c);

  5. for(int i=1;i<=n;i++)

  6. for(int k=1;k<=n;k++)

  7. for(int j=1;j<=n;j++)

  8. c[i][j]+=a[i][k]*b[k][j];

  9. }

這種可以在第二重for判斷if(a[i][k]==0)continue;對於矩陣有較多0的有一定效果。不過一般第一種寫法就夠了,這種知道就行。

 

顯然矩陣乘法的複雜度是O(n^3);(O(n^2.7)的方法不會寫,無視這裏)。

這裏我直接寫的是n*n的矩陣(即方陣),顯然兩個相乘是要一行和一列對應乘,那麼矩陣乘法是需要A的行數與B的列數相等的(這是A*B的前提條件,可見矩陣的乘法是不滿足交換律的)。然而這些一般都是沒什麼用的,矩陣快速冪只會用到方陣(除非題目是裸的矩陣乘法)。矩陣快速冪都是方陣也就避免的相乘的前提條件,可以放心用。

 

(1)矩陣快速冪

就是算A^n;方法很簡單,把快速冪算法中的乘法改成矩陣的乘法就可以了

代碼:


 
  1. const int N=10;

  2. int tmp[N][N];

  3. void multi(int a[][N],int b[][N],int n)

  4. {

  5. memset(tmp,0,sizeof tmp);

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

  7. for(int j=0;j<n;j++)

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

  9. tmp[i][j]+=a[i][k]*b[k][j];

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

  11. for(int j=0;j<n;j++)

  12. a[i][j]=tmp[i][j];

  13. }

  14. int res[N][N];

  15. void Pow(int a[][N],int n)

  16. {

  17. memset(res,0,sizeof res);//n是冪,N是矩陣大小

  18. for(int i=0;i<N;i++) res[i][i]=1;

  19. while(n)

  20. {

  21. if(n&1)

  22. multi(res,a,N);//res=res*a;複製直接在multi裏面實現了;

  23. multi(a,a,N);//a=a*a

  24. n>>=1;

  25. }

  26. }

這代碼看看就好,我的寫法一般人不是很喜歡看,網上有很多種寫法,比如用結構體存矩陣什麼的,模板建議還是自己寫的好,自己怎麼寫順溜就怎麼寫唄,弄清楚原理就好。

 

不過上訴res數組就等同於普通快速冪初始化的1,原理想通的,這個矩陣叫單位矩陣E,性質就是E*A=A,就是1*a=a,一樣,單位矩陣就是對角線全是1其他全是0;

最終算出的結果是一個res矩陣,具體有什麼用就看下面的應用。

應用篇

主要通過把數放到矩陣的不同位置,然後把普通遞推式變成"矩陣的等比數列",最後快速冪求解遞推式:

先通過入門的題目來講應用矩陣快速冪的套路(會這題的也可以看一下套路):

例一:http://poj.org/problem?id=3070
題目:斐波那契數列f(n),給一個n,求f(n)%10000,n<=1e9;

(這題是可以用fibo的循環節去做的,不過這裏不講,反正是水題)

矩陣快速冪是用來求解遞推式的,所以第一步先要列出遞推式:

 f(n)=f(n-1)+f(n-2)

第二步是建立矩陣遞推式,找到轉移矩陣:

,簡寫成T * A(n-1)=A(n),T矩陣就是那個2*2的常數矩陣,而

這裏就是個矩陣乘法等式左邊:1*f(n-1)+1*f(n-2)=f(n);1*f(n-1)+0*f(n-2)=f(n-1);

這裏還是說一下構建矩陣遞推的大致套路,一般An與A(n-1)都是按照原始遞推式來構建的,當然可以先猜一個An,主要是利用矩陣乘法湊出矩陣T,第一行一般就是遞推式,後面的行就是不需要的項就讓與其的相乘係數爲0。矩陣T就叫做轉移矩陣(一定要是常數矩陣),它能把A(n-1)轉移到A(n);然後這就是個等比數列,直接寫出通項:此處A1叫初始矩陣。所以用一下矩陣快速冪然後乘上初始矩陣就能得到An,這裏An就兩個元素(兩個位置),根據自己設置的A(n)對應位置就是對應的值,按照上面矩陣快速冪寫法,res[1][1]=f(n)就是我們要求的。

 

給一些簡單的遞推式
1.f(n)=a*f(n-1)+b*f(n-2)+c;(a,b,c是常數)

2.f(n)=c^n-f(n-1) ;(c是常數)

繼續例題二:poj3233

 

Description

Given a n × n matrix A and a positive integer k, find the sum S = A + A2 + A3 + … + Ak.

Input

The input contains exactly one test case. The first line of input contains three positive integers n (n ≤ 30), k (k ≤ 109) and m (m < 104). Then follow n lines each containing n nonnegative integers below 32,768, giving A’s elements in row-major order.

Output

Output the elements of S modulo m in the same way as A is given

這題就是求一個矩陣的和式:S(k),直接對和式建立遞推:

建立矩陣,注意此處S和A都是2*2的矩陣,E表示單位矩陣,O表示零矩陣(全是0,與其他矩陣相乘都爲0),顯然E,O都是2*2的

這裏轉移矩陣是4*4.OVER

 

一般這種題目都是要找遞推式,這是難點.

例三:HDU2276

題意就是說n個燈排成環i號燈的左邊是i-1號,1的左邊是n號,給定初始燈的開閉狀態(用1,0表示),然後每一秒都操作都是對於每個燈i,如果它左邊的燈是開的就把i狀態反轉(0變1,1變0),問m秒都最終狀態是什麼,m<=1e8,n<=100;

這題的遞推式沒有明說,但是每一秒操作一次其實就是一次遞推,那麼關鍵就是要找轉移矩陣,而且比較是常數矩陣,這個才能用等比的性質

我們把n個燈的狀態看出一個F(n),其實就是一個n*1的01矩陣,然後考慮從上一秒的狀態F(n-1)如何轉移到F(n)。既然每個狀態都要轉移,總共n個狀態,可以看出轉移矩陣就是一個n*n的矩陣(每一個燈的狀態都用一個1*n的矩陣來轉移)

先考慮第一個燈:影響它新狀態的只有它左右的燈和它自己的狀態,仔細想一下,1*n的轉移中只有這兩位置有用,那麼其他都是0,就這樣

這裏state2到staten-1都被0幹掉了,只有第一個和1號左邊的燈有效

(這裏不具體講了,只有0,1的狀態,自己枚舉一下state1和state2,矩陣相乘後都是能正確轉移的)

其他燈的考慮都是一樣的,最終:

OVER

 

例四:HDU 5015
題意就是一個矩陣a,第一行依次是0,233,2333,23333......,給出矩陣的遞推式:a[i][j]=a[i-1][j]+a[i][j-1],輸入的是第零列,求a[n][m],n ≤ 10,m ≤ 109
解:n很小,m很大,m大概就是作爲冪次,以每一列爲一個矩陣A(n-1)並且向下一列A(n)轉移,那麼關鍵就是找轉移矩陣了:
先看第一行的數233後面每次都添一個3,顯然遞推關係就是A(n-1)*10+3=A(n),這裏多一個3,必須把列數新增一個元素3,也就是一個(n+1)*1的矩陣A(n).
然後其他的元素轉移會出現一個問題,a[i][j]=a[i-1][j]+a[i][j-1];這裏a[i-1][j]依舊是新一列的元素,這是不能矩陣轉移的,因爲矩陣轉移必須從舊的矩陣狀態A(n-1)變到新狀態A(n)。
那麼這裏a[i-1][j]就用遞歸思想,沿用上一行的轉移矩陣(上一行能轉移出a[i-1][j]),再加上新增的轉移:

 

OVER

當然矩陣還有很多奇葩的遞推,比如這矩陣優化的dp題

推薦一些題目:

簡單的:

http://acm.hdu.edu.cn/showproblem.php?pid=1757

http://acm.hdu.edu.cn/showproblem.php?pid=1575

不簡單的:

http://acm.hdu.edu.cn/showproblem.php?pid=3483

http://acm.hdu.edu.cn/showproblem.php?pid=2855

http://acm.hdu.edu.cn/showproblem.php?pid=3658

http://acm.hdu.edu.cn/showproblem.php?pid=4565

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章