【Matrix】矩陣乘法

矩陣乘法: 

Mat Mult(Mat a, Mat b){  // Mat 爲自定義類型
    Mat c;
    memset(c.m, 0, sizeof(c.m));
    c.r= a.r;  c.c=b.c;  // 新的矩陣的行列
    for(int i=0; i<=c.r; i++){
            for(int j=0; j<=c.c; j++){
                    for(int k=0; k<=a.c; k++)
                            c.m[i][j]= (c.m[i][j]+a.m[i][k]*b.m[k][j]);
                    }
            }
    return c;
}

快速冪:

Mat Calc(int x){
     if(x==1) {
              return yuan;  // 原始矩陣
              }
     Mat ret= Calc(x/2);
     ret= Mult(ret, ret);
     if(x%2==1) ret=Mult(ret, yuan);
     return ret;
     }

 

snack:

給定一個有向圖, 問在規定時間從起點出發沿邊行走並收集所有物品(邊上有一定的物品,收集花費時間2,否則花費時間1)的總方案數。

時間  10^9,   物品4,  頂點數爲25

考慮DP:  f[i,  j, k](i   所在頂點,   j 經過時間,     k收集物品的狀態)  =  { f[v,      j-1,    k]  }+  {  f[v,  j-2,  x] } 分別爲收集該邊和不收集改邊,  由於時間一維巨大, 考慮使用矩陣乘法。

定義一維矩陣G= {sum,    f1,   f2,   f3 …, fn ,   g1,   g2,   g3, … gn} 爲到頂點1的總方案數,  時間i的每個頂點的每種狀態, i-1時間的頂點與狀態。

於是可以構造一個二位矩陣M { 符合上面的運算的 }  

分析時間複雜度  25* 16 * 2+ 1= 801    O(N^3)的時間複雜度接受不了。

 

所以可以考慮容斥原理:  把ABCD含都加進方案裏,再把ABC, ABD,  ACD , BCD減去 ……

這樣構造矩陣的時候比較和諧, 時間複雜度也變成了 O(16 *  (25*2+1)^3 *  log2(10^9) )

代碼:

#include<cstdio>
#include<cstring>
using namespace std;

#define N 25
#define M 51
#define Edge 500
#define Mod 5557

struct Mat{ int m[M][M], r , c ;};

const int data[16]={1, -1, -1 , 1, -1, 1, 1,-1, -1, 1, 1, -1, 1, -1, -1, 1};

Mat yuan, I;

int n,m,T;
int state[Edge], x[Edge], y[Edge];

int Change(char c){
    if (c=='B') return 1;     if (c=='J') return 2;
    if (c=='M') return 4;     if (c=='P') return 8;
    }

void Make_State(int &s){
     char c;       while(c=getchar(), c<'A' ||  c>'Z');
     s=Change(c);  while(c=getchar(), c>='A'&& c<='Z') s+=Change(c);
     }

void Init(){
     scanf("%d%d",&n,&m);
     for(int i=0;i<m;i++){
             scanf("%d%d",&x[i],&y[i]);
             Make_State(state[i]);
             }
     scanf("%d",&T);
     }
     
Mat Mult(Mat a, Mat b){
    Mat c;
    memset(c.m, 0, sizeof(c.m));
    c.r= a.r;  c.c=b.c;
    for(int i=0; i<=c.r; i++){
            for(int j=0; j<=c.c; j++){
                    for(int k=0; k<=a.c; k++)
                            c.m[i][j]= (c.m[i][j]+a.m[i][k]*b.m[k][j]) % Mod;
                    }
            }
    return c;
}

Mat Calc(int x){
     if(x==1) {
              return yuan;
              }
     Mat ret= Calc(x/2);
     ret= Mult(ret, ret);
     if(x%2==1) ret=Mult(ret, yuan);
     return ret;
     }
     
void mat(int S){
     memset(yuan.m, 0, sizeof(yuan.m));
     yuan.r=yuan.c=2*n;
     yuan.m[0][0]= yuan.m[0][1]=1;
     for(int i=1; i<=n; i++){yuan.m[n+i][i]=1;}
     for(int i=0; i<m; i++){
             int u=x[i], v=y[i];
             yuan.m[v][u] =1;  
             if((state[i] | S)==S) yuan.m[v][u+n] =1;
             }
     }  
	   
int Solve(){
    Mat amat=Calc(T+1);
    memset(I.m, 0, sizeof(I.m));
    I.r=n*2, I.c=0, I.m[0][0]=0; I.m[1][0]=1;
    Mat ans= Mult(amat, I);
    return ans.m[0][0];
    }
         
void Work(){
     int Ans=0;
     for(int i=0;i<=15;i++){
             mat(15-i);
             int tt=Solve();
             Ans= (Ans+ data[i]*tt ) % Mod;
             }
     Ans= (Ans+Mod)%Mod;
     printf("%d\n",Ans);
     }

int main(){

    Init();
    Work();

    return 0;
}


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