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; }