2013-team4/code/matrix

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

{{{
矩阵快速幂
}}}
{{{
typedef int DATA;
const int MAXN = 202;

struct mat{
    int n;
    DATA v[MAXN][MAXN];
    mat(int n, bool one = false){
        this->n = n;
        memset(v, 0, sizeof(v));
        if(one) for(int i = 0; i < n; i++) v[i][i] = 1;
    }
    mat operator*(const mat &a) const{
        mat ret(n);
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                for(int k = 0; k < n; k++)
                    ret.v[i][j] += v[i][k] * a.v[k][j];
        return ret;
    }
    mat operator^(int p) const{
        mat ret(n, true), a = (*this);
        while(p > 0){
            if(p & 1)
                ret = ret * a;
            p >>= 1;
            a = a * a;
        }
        return ret;
    }
};
}}}
{{{
列主元法求逆矩阵
}}}
{{{
#include <vector>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cassert>
using namespace std;
typedef long double Double;
typedef vector<Double> VD;
typedef vector<VD> VVD;
#define ONE 1
#define ZERO 0
#define REP(i,n) for(int i=0; i<int(n); i++)
#define eps 1e-10
inline int sgn(double x){
    if(fabs(x)<eps)return 0;
    else return x>0?1:-1;
}

class Matrix{
public:
    VVD data;
    VD &operator[](size_t i){return data[i];}
    Matrix(size_t n, size_t m, int type=0){
        data=VVD(n,VD(m,0));
        switch(type){
            case ONE: {
                int nn=min(n,m);
                REP(i,nn)data[i][i]=1;
                break;
            }
            case ZERO: break;
            default: assert(type==ONE||type==ZERO);
        }
    }
    Matrix(const VVD &d):data(d){}
    Matrix(const Matrix &A):data(A.data){}

    size_t size(){return data.size();}

    void print(void){
        for(size_t i=0; i<data.size(); i++){
            for(size_t j=0; j<data[i].size(); j++)
                printf("%.2lf ",data[i][j]);
            printf("\n");
        }
    }

    bool isSquare(){
        if(data.size()==0)return true;
        else if(data.size()==data[0].size())return true;
        else return false;
    }

    //return value means whether this method is working properly
    bool transpose(void){
        if(!isSquare())return false;
        for(size_t i=0; i<data.size(); i++){
            for(size_t j=i+1; j<data.size(); j++)
                swap(data[i][j],data[j][i]);
        }
        return true;
    }

    void swapRow(size_t i, size_t j){swap(data[i],data[j]);}
    void mulRow(size_t i, Double times){REP(j,data[i].size())data[i][j]*=times;}
    //add times*Row i to row j
    void addMulRow(Double times, size_t i, size_t j)
    {REP(k,data[i].size())data[j][k]+=data[i][k]*times;}

    bool invert(Matrix &M){
        if(!isSquare())return false;
        int n=data.size();
        M=Matrix(n, n, ONE);
        REP(k, n){//kth column
            int row=k; Double maxv=fabs(data[k][k]);
            for(size_t i=k+1; i<n; i++)//Find the maximum element in the kth column
                if(fabs(data[i][k])>maxv)maxv=data[row=i][k];
            if(sgn(maxv)==0)return false;
            swapRow(k, row);
            M.swapRow(k, row);
            maxv=data[k][k];
            for(size_t i=0; i<n; i++){
                if(i==k)continue;
                Double t=-data[i][k]/maxv;
                addMulRow(t, k, i);
                M.addMulRow(t, k, i);
                assert(sgn(data[i][k])==0);
            }
            mulRow(k, 1/maxv);
            M.mulRow(k, 1/maxv);
        }
        return true;
    }
};

int main(){
    int n;
    scanf("%d",&n);
    Matrix A(n,n);
    REP(i,n)REP(j,n)
        cin>>A[i][j];
    A.transpose();
    Matrix M(0,0);
    if(A.invert(M)){
        /*A.print();
        printf("-------\n");
        M.print();*/
        bool flag=false;
        REP(i,M.size()){
            REP(j,M[i].size()){
                if(sgn(round(M[i][j])-M[i][j])!=0)flag=true;
            }
        }
        if(flag)printf("Power of magic saves lives\n");
        else printf("Death\n");
    } else {
        printf("Power of magic saves lives\n");
    }
}
}}}
矩阵快速幂
typedef int DATA;
const int MAXN = 202;
struct mat{
    int n;
    DATA v[MAXN][MAXN];
    mat(int n, bool one = false){
        this->n = n;
        memset(v, 0, sizeof(v));
        if(one) for(int i = 0; i < n; i++) v[i][i] = 1;
    }
    mat operator*(const mat &a) const{
        mat ret(n);
        for(int i = 0; i < n; i++)
            for(int j = 0; j < n; j++)
                for(int k = 0; k < n; k++)
                    ret.v[i][j] += v[i][k] * a.v[k][j];
        return ret;
    }
    mat operator^(int p) const{
        mat ret(n, true), a = (*this);
        while(p > 0){
            if(p & 1)
                ret = ret * a;
            p >>= 1;
            a = a * a;
        }
        return ret;
    }
};
列主元法求逆矩阵
#include <vector>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cassert>
using namespace std;
typedef long double Double;
typedef vector<Double> VD;
typedef vector<VD> VVD;
#define ONE 1
#define ZERO 0
#define REP(i,n) for(int i=0; i<int(n); i++)
#define eps 1e-10
inline int sgn(double x){
    if(fabs(x)<eps)return 0;
    else return x>0?1:-1;
}
class Matrix{
public:
    VVD data;
    VD &operator[](size_t i){return data[i];}
    Matrix(size_t n, size_t m, int type=0){
        data=VVD(n,VD(m,0));
        switch(type){
            case ONE: {
                int nn=min(n,m);
                REP(i,nn)data[i][i]=1;
                break;
            }
            case ZERO: break;
            default: assert(type==ONE||type==ZERO);
        }
    }
    Matrix(const VVD &d):data(d){}
    Matrix(const Matrix &A):data(A.data){}
    size_t size(){return data.size();}
    void print(void){
        for(size_t i=0; i<data.size(); i++){
            for(size_t j=0; j<data[i].size(); j++)
                printf("%.2lf ",data[i][j]);
            printf("\n");
        }
    }
    bool isSquare(){
        if(data.size()==0)return true;
        else if(data.size()==data[0].size())return true;
        else return false;
    }
    //return value means whether this method is working properly
    bool transpose(void){
        if(!isSquare())return false;
        for(size_t i=0; i<data.size(); i++){
            for(size_t j=i+1; j<data.size(); j++)
                swap(data[i][j],data[j][i]);
        }
        return true;
    }
    void swapRow(size_t i, size_t j){swap(data[i],data[j]);}
    void mulRow(size_t i, Double times){REP(j,data[i].size())data[i][j]*=times;}
    //add times*Row i to row j
    void addMulRow(Double times, size_t i, size_t j)
    {REP(k,data[i].size())data[j][k]+=data[i][k]*times;}
    bool invert(Matrix &M){
        if(!isSquare())return false;
        int n=data.size();
        M=Matrix(n, n, ONE);
        REP(k, n){//kth column
            int row=k; Double maxv=fabs(data[k][k]);
            for(size_t i=k+1; i<n; i++)//Find the maximum element in the kth column
                if(fabs(data[i][k])>maxv)maxv=data[row=i][k];
            if(sgn(maxv)==0)return false;
            swapRow(k, row);
            M.swapRow(k, row);
            maxv=data[k][k];
            for(size_t i=0; i<n; i++){
                if(i==k)continue;
                Double t=-data[i][k]/maxv;
                addMulRow(t, k, i);
                M.addMulRow(t, k, i);
                assert(sgn(data[i][k])==0);
            }
            mulRow(k, 1/maxv);
            M.mulRow(k, 1/maxv);
        }
        return true;
    }
};
int main(){
    int n;
    scanf("%d",&n);
    Matrix A(n,n);
    REP(i,n)REP(j,n)
        cin>>A[i][j];
    A.transpose();
    Matrix M(0,0);
    if(A.invert(M)){
        /*A.print();
        printf("-------\n");
        M.print();*/
        bool flag=false;
        REP(i,M.size()){
            REP(j,M[i].size()){
                if(sgn(round(M[i][j])-M[i][j])!=0)flag=true;
            }
        }
        if(flag)printf("Power of magic saves lives\n");
        else printf("Death\n");
    } else {
        printf("Power of magic saves lives\n");
    }
}