矩阵快速幂 ZOJ 2853 Evolution

题意:

演变

有n个物种,编号分别是1~n-1,每个物种的初始数量为d[i],i属于[0,n-1], 整个演变过程分为n个相同的”小演变“。

一次”小演变“又有T个步骤:

每个步骤形如  i   j   p[i][j] ;

i,j是两个物种(i<>j) ,p[i][j]=0.65 表示有 65%的物种i 变成了物种j,其中p[i][j]范围是[0,1]。且T个步骤不会形成一个环。

现在问,经过n次"小演变"后,第n个物种的数量。

N<=200,M<=10^5

 

题解:

这是经典的矩阵快速幂,重点在矩阵的构造。看下下面的例子。

对于例子

n m : 3 1

d[i]: 40 20 10

T : 3

T1:0 1 p1

T2:1 2 p2

T3:0 2 p3


我们可以写出矩阵的计算过程:

s,这里的A,B,C 对应d[0],d[1]和d[2].   理解这个例子后,可以很容易总结出矩阵的构造方式!

 

由于这两天ZOJ 居然出问题啦,所以过几天再去提交AC代码!

代码:


#include <iostream>
#include <cstdio>
#include<cstring>
#define MaxN 205
int Nsize;
double p[MaxN][MaxN];

struct Mat{
    double mat[MaxN][MaxN];
};

Mat operator * (Mat a,Mat b){
    Mat c;
    memset(c.mat,0,sizeof(c.mat));
    
    for(int k=0;k< Nsize;k++)
        for(int i=0;i< Nsize;i++){
            
            if(a.mat[i][k]<=0) continue; //剪枝
            for(int j=0;j< Nsize;j++){
                
                if(b.mat[k][j]<=0) continue;//剪枝
                c.mat[i][j]+= a.mat[i][k]*b.mat[k][j];
            }
        
        }
    
    return c;
}


Mat operator ^ (Mat a,int k){
    Mat c;
    for(int i=0;i< Nsize;i++)
        for(int j=0;j< Nsize;j++)
            c.mat[i][j]= (i==j) ;  //单位矩阵
    
    for(;k;k>>=1){
        if(k&1) c=c*a;
        a=a*a;
    }
    
    return c;
}


int main(int argc, const char * argv[]) {
    
    int n,m,T;
    
    while(~scanf("%d%d",&n,&m)){
    
        if(!n && !m) break;
        
        Nsize=n;
        Mat d;
        for(int i=0;i<n;i++)
            scanf("%lf",&d.mat[i][0]);
        
        scanf("%d",&T);
        
        Mat a;
        memset(a.mat,0,sizeof(a.mat));
        for(int i=0;i< n;i++)
            a.mat[i][i]=1;
        
        int u,v;
        double x;
        while(T--)
        {
            scanf("%d%d%lf",&u,&v,&x);
            a.mat[v][u]+=x;
            a.mat[u][u]-=x;
            if(a.mat[u][u]<0) a.mat[u][u]=0;
        }
        
        Mat res;
        res=(a^m)*d;
        
        printf("%.0f\n",res.mat[n-1][0]);
    
    }
    
    
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值