题意:
演变
有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
我们可以写出矩阵的计算过程:
,这里的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;
}