DG之童年的游戏  矩阵连乘 + 坐标变换

题目来源:

http://acm.seu.edu.cn/oj/problem.php?id=49

 

坐标变换为:

所以我们知道 转移矩阵分别为:

第i个人加1(eg.第2个人)

1 0 0

0 1 1

0 0 1

第2个人变0

1 0 0

0 0 0

0 0 1

第2个人与第1个人交换(第二行与第一行交换)

0 1 0

1 0 0

0 0 1

 

代码如下:

 

#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <stdio.h>
#include <stack>
#include <string>
#include <string.h>
#include<cstring>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <set>
#include <math.h>
#include <cmath>
#include <map>
#include <queue>
using namespace std ;
typedef long long LL ;
const int Max_N = 104;
int  n ;

struct Mat{     // 矩阵下标从1开始 - n
    LL elem[Max_N][Max_N];
    Mat(){ //全0矩阵
        memset(elem, 0, sizeof(elem));
    }
    void DigOne(){ //单位矩阵
        for(int i = 1 ; i <= n ; i++) elem[i][i] = 1 ;
    }
};

Mat operator * (Mat a , Mat b){
    Mat s;
    for(int i=1; i <= n  ; i++){
        for(int j=1; j <= n; j++){
            if(a.elem[i][j] == 0) continue ; //稀疏矩阵
            for(int k=1; k <= n ; k++){
                s.elem[i][k] +=  a.elem[i][j] * b.elem[j][k];
            }
        }
    }
    return s;
}

Mat operator ^ (Mat x , int  y){
    Mat s ;
    s.DigOne() ;
    for(; y ; y >>= 1 , x = x * x){
        if(y&1) s = s * x ;
    }
    return s;
}

int main(){
    int  m , k ,  i , j , t ;
    char s[3];
    while(scanf("%d%d%d",&n,&m,&k)){
        if(n==0 && m==0 && k==0)
            break;
        n++ ;
        Mat O ;
        O.DigOne() ;
        for(t = 1 ; t <= k ; t++){
            scanf("%s",s);
            if(s[0] == 'a'){
                scanf("%d" , &i);
                Mat A ;
                A.DigOne() ;
                A.elem[i][n]=1;
                O = A * O ;
            }
            else if(s[0] == 'b'){
                scanf("%d",&i);
                Mat A ;
                A.DigOne() ;
                A.elem[i][i]=0;
                O = A * O ;
            }
            else{
                scanf("%d%d", &i , &j);
                Mat A ;
                A.DigOne() ;
                A.elem[i][i]=0  , A.elem[i][j]=1;
                A.elem[j][i]=1  , A.elem[j][j]=0;
                O = A * O ;
            }
        }
        O = O ^ m ;
        for(i=1 ; i< n-1 ; i++)
            printf("%lld ", O.elem[i][n]);
        printf("%lld\n", O.elem[n-1][n]);
    }
    return 0;
}

 

 

poj 3070 Fibonacci    矩阵连乘 + mod 求余

题目来源:
http://poj.org/problem?id=3070

 

代码如下:

 

using namespace std ;
typedef long long LL ;
const double EPS = 1e-10;
const int Max_N = 104;
const int Mod = 10000;
struct Mat{
    int mat[2][2];
    Mat operator * (Mat m){ // 矩阵相乘double型
        Mat ans={0, 0, 0, 0};
        for(int i = 0; i<2 ; i++)
            for(int j=0; j<2; j++)
                if(mat[i][j] > EPS) // 剪枝
                    for(int k=0; k<2; k++)
                        ans.mat[i][k]= (ans.mat[i][k] +mat[i][j]*m.mat[j][k] ) % Mod ;
        return ans;
    }
}unit={1,0,0,1};
// 矩阵幂乘
Mat operator ^(Mat m, int b){ // b>0
    Mat p = m,ans = unit;
    for(; b>0 ; b>>=1, p=p*p)
        if(b&1)
            ans=ans*p;
    return ans;
}
int main(){
    int n;
    while(scanf("%d",&n) && n!= -1){
        if(n == 0) {puts("0");continue;}
        if(n== 1)  {puts("1"); continue;}
        Mat res={1,1,1,0};
        res=res^(n-1);
        cout<<res.mat[0][0]<<endl;
    }
    return 0;
}

 

 zoj  2853 Evolution    矩阵连乘  +  double 型

题目来源:

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1853

代码如下:

const double EPS = 1e-12;
const int Max_N = 202;
int n;
struct Mat{
    double elem[Max_N][Max_N];
    void read(){
        for(int i=0; i<n; i++){
            for(int j=0; j<n; j++)
                printf("%lf ",elem[i][j]);
            puts("");
        }

    }

};
Mat Zero(){
    Mat ans;
    for(int i=0; i<n; i++){
        for(int j=0; j<n; j++){
                ans.elem[i][j] = 0;
        }
    }
    return ans;
}
Mat One(){
    Mat ans;
    for(int i=0; i<n; i++){
        for(int j=0; j<n; j++){
                ans.elem[i][j] = (i==j);
        }
    }
    return ans;
}
Mat operator * ( Mat a, Mat b){
    Mat ans; ans=Zero();
    for(int i=0; i<n; i++){
        for(int j=0; j<n; j++){
                if( fabs(a.elem[i][j])>EPS  )
                    for(int k=0; k<n; k++){
                        ans.elem[i][k] += a.elem[i][j] * b.elem[j][k];
                    }
        }
    }
    return ans;
}
Mat operator ^ ( Mat x, int y){
    Mat ans; ans = One();
    for(; y ; y>>=1, x= x*x)
        if(y & 1)
            ans=ans*x;
    return ans;
}
double data[Max_N];
int main(){
    int m,t,x,y;
    double p;
    while(scanf("%d%d",&n,&m)){
        if(n==0 && m==0)
            break;
        Mat res;
        res=One();
        for(int i=0; i<n; i++)
            scanf("%lf",&data[i]);
        scanf("%d",&t);
        while(t--){
            scanf("%d%d%lf",&x,&y,&p);
            res.elem[y][x] +=p;
            res.elem[x][x] -=p;
        }
       // res.read();
        res = res^m;
        double sum=0;

        for(int i=0; i<n; i++){
            sum += res.elem[n-1][i]*data[i];
        }
        printf("%.0lf\n",sum);
    }

    return 0;
}