矩阵乘法 经典题目

1。  给定一个有向图,问从A点恰好走k步(允许重复经过边)到达B点的方案数mod p的值  

把给定的图转为邻接矩阵,即A(i,j)=1当且仅当存在一条边i->j。令C=A*A,那么C(i,j)=ΣA(i,k)*A(k,j),实际上就等于从点i到点j恰好经过2条边的路径数(枚举k为中转点)。类似地,C*A的第i行第j列就表示从i到j经过3条边的路径数。同理,如果要求经过k步的路径数,我们只需要二分求出A^k即可。

--摘自,http://www.matrix67.com/blog/archives/276/

理解:

为什么k步的路径数,我们只需要二分求出A^k?

因为每步实际做一次矩阵乘法,矩阵乘法定义就是C(i,j)=ΣA(i,k)*A(k,j)。

2.经典题目9 用1 x 2的多米诺骨牌填满M x N的矩形有多少种方案,M<=5,N<2^31,输出答案mod p的结果

 

View Code
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
#include<vector>
#include<string>
#include<math.h>
#include<map>
#include<set>
#include<algorithm>
using namespace std;

#define MAXN 258
#define MOD 9937
#define size (1<<M)
int N, M;
int ans[1200];


class Matrix
{
  public:
    int mt[MAXN][MAXN];
    Matrix  Multiply(Matrix);
    Matrix  Add(Matrix);
    Matrix  quickpower(int);
}AA;



Matrix Matrix::Add(Matrix A)
{
   Matrix C;
   for( int i = 1; i <= size; i++)
     for( int j = 1; j <= size; j++)
         C.mt[i][j] = mt[i][j] + A.mt[i][j];                     
   return C;
}

Matrix Matrix::Multiply(Matrix A)
{
   Matrix C;
   for( int i = 0; i < size; i++)
   {
       for( int j = 0; j < size; j++)
       {
            
            int sum = 0;
            for( int k = 0; k < size; k++)
            {
              if( A.mt[i][k] && mt[k][j] )
              {    
               sum += (A.mt[i][k] % MOD) * (mt[k][j] % MOD);
               sum %= MOD;
               }
                 
            }     
            C.mt[i][j] = sum;
            
       }     
        
        
   }
   return C;     
}

Matrix Matrix::quickpower(int n)
{
  Matrix B;
  B = *this;
  while( n > 0 )
  {
     if( n & 1 )
         *this = (*this).Multiply(B);
     n = n / 2;
     B = B.Multiply(B);             
  }
  return *this;
}

//横的摆放状态 
void pre(int x, int state)
{
  if( x > M )
      return;
  if( x == M )
  {
    ans[state] = 1;
    return;
  }
  pre(x + 1, state << 1 );
  pre(x + 2, 3 | (state << 2) ); 
}

int main( )
{
  while( scanf("%d%d",&N,&M) != EOF )
  {
    if( N < M )
        swap(N,M);
    memset(ans, 0, sizeof(ans));
    pre(0, 0);
    if( N % 2 == 1 && M % 2 == 1 )
    {
       puts("0"); continue;
    }
    for( int i = 0; i < (1<<M); i++)
    {
        for( int j = 0; j < (1<<M); j++)
        {   
            AA.mt[i][j] = 0;
            if( ((~i)&j) == ((~i)&((1<<M)-1)) )
            {
                 AA.mt[i][j] = ans[i&j];     
            }     
        }     
    }
    AA = AA.quickpower(N-1);
    printf("%d\n",AA.mt[(1<<M)-1][(1<<M)-1]);       
  }  
  return 0;
}

 

 

 

 

 

posted on 2012-08-17 11:31  more think, more gains  阅读(340)  评论(0编辑  收藏  举报

导航