九度 题目1443:Tr A

原题地址:http://ac.jobdu.com/problem.php?pid=1443
题目1443:Tr A
时间限制:1 秒内存限制:128 兆特殊判题:否提交:1396解决:825
题目描述:
A为一个方阵,则Tr A表示A的迹(就是主对角线上各项的和),现要求Tr(A^k)%9973。
输入:
数据的第一行是一个T,表示有T组数据。
每组数据的第一行有n(2 <= n <= 10)和k(2 <= k < 10^9)两个数据。接下来有n行,每行有n个数据,每个数据的范围是[0,9],表示方阵A的内容。
输出:
对应每组数据,输出Tr(A^k)%9973。
样例输入:
2
2 2
1 0
0 1
3 99999999
1 2 3
4 5 6
7 8 9
样例输出:
2
2686
题目分析:
题目要求一个n×n方阵的k次方,n(2 <= n <= 10),k(2 <= k < 10^9);
特点是n很小,k很大,矩阵中数据范围也很小[0,9]。
k比较大即幂次较大,因此考虑用二分求幂的方法来降低求幂的次数。
因为矩阵中数据范围很小,所以不必考虑矩阵中的数据会溢出。
代码:

#include <iostream>
#include <math.h>
#include <string.h>
#include <vector>
#include <queue>
#include <map>
#include<stdio.h>
#define M 9973
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
struct metric{
    int num[12][12];
    int n;  //方阵的大小 
    void init(int n){
        this->n=n; 
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                num[i][j]=0;
            }
        }
    }
    void init(int n,int x){
        init(n);
        for(int i=0;i<n;i++){
                num[i][i]=x;
        }
    }
    int getTr(){
        int ans=0;
        for(int i=0;i<n;i++){
                ans=(ans+num[i][i])%M;  //主对角线和 
        }
        return ans;
    }
    metric operator*(const metric &A)const{
        //矩阵乘法 
            metric ans;
            ans.init(n);

            for(int i=0;i<n;i++){  //遍历第一个矩阵的每一行的每一列 
                for(int j=0;j<n;j++){
                    for(int k=0;k<A.n;k++){  //遍历第二个矩阵的每一列                  
                        ans.num[i][j]+=((num[i][k]%M)*(A.num[k][j]%M))%M;   
                    }
                } 
            }
            return ans; 
    }
    void output(){
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                cout<<num[i][j];
                cout<<" ";
            }
            cout<<endl;
        }
        cout<<endl;
    }
}; 
int main(int argc, char *argv[]) {
    int T;
    cin>>T;
    while(T--){
        int n,k;
        cin>>n>>k;
        {
            //初始化矩阵 
            metric A;
            A.init(n);
            for(int i=0;i<n;i++){
                for(int j=0;j<n;j++){
                    cin>>A.num[i][j];
                }
            }
            //A=A*A;
            //A.output();
            //二分法求矩阵ans的k阶乘
            metric ans;
            ans.init(n,1);
            //ans.output();
            while(k!=0){
                if(k%2 == 1){
                    //ans.output();
                    //A.output();
                    ans=ans*A;
                    //ans.output();
                }

                A=A*A;
                k/=2;
            } 
            //ans.output();
            //求主对角线之和 
            cout<<ans.getTr()<<endl; 
        }
    }
    return 0;
}

独特的收获:
要实现矩阵的乘法,就需要按照矩阵乘法的规则进行操作。
在三个for循环过程中总结出一个分析多重for循环的方法,如下:
用题目中矩阵乘法部分的for循环来举例,

 for(int i=0;i<n;i++){  //遍历第一个矩阵的每一行的每一列 
                for(int j=0;j<n;j++){
                    for(int k=0;k<A.n;k++){  //遍历第二个矩阵的每一列                  
                        ans.num[i][j]+=((num[i][k]%M)*(A.num[k][j]%M))%M;   
                    }
                } 
            }

分析过程如下:
i=0 j=0 k=0 ans[0,0]= A[ 0 , 0 ] * B[ 0 , 0 ]
k=1 ans[0,0]= A[ 0 , 0 ] * B[ 0 , 1 ]
j=1 k=0 ans[0,1]= A[ 0 , 0 ] * B[ 0 , 1 ]
k=1 ans[0,0]= A[ 0 , 1 ] * B[ 1 , 1 ]
i=1 j=0 k=0
k=1
j=1 k=0
k=1
对比左右两部分即可发现i,j,k和矩阵乘法在三个for循环中应该具有的关系,即i控制第一个矩阵的行,j控制第二个矩阵的列,k控制第一个矩阵的列和第二个矩阵的行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值