题目链接
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1853
思路
题意是n个物种,m次进化,给你每次进化的变换P(i,j),表示每次有P(i,j)的i物种变到了j物种,给你每个物种的初始数量,问m次进化后,第n-1个物种的数量是多少。
这相当于对原来的物种数量做多次线性变换,我们定义一个矩阵,其中 aij 表示每次j物种有多少变成了i物种,我们每读一个P(i,j)就把 aji 赋上相应的值,最后把 ajj 填上1减去所有的 akj,k∈[0,n−1],k≠j 。然后把这个变换矩阵快速幂m次方,最后乘上原式数量矩阵即可。
注意矩阵有点大直接开在main里会爆栈,开到外面就好了。
还有据说参数如果是形参的话是储存在栈里的,参数太大会爆,改成引用就行了,我这里没爆就不改了。
然后有个小坑点就是四舍五入到整数,我一开始floor(ans+0.5)WA了,改成%.0f就对了,可能是精度误差问题,以后还是都用%.0f吧保险点。
AC代码
#include <bits/stdc++.h>
using namespace std;
struct matrix
{
double mat[210][210];
int m,n;
matrix(int h, int w)
{
for(int i=0 ; i<h ; ++i)
for(int j=0 ; j<w ; ++j)
mat[i][j]=0;
m=h;
n=w;
}
void reset(int h, int w)
{
for(int i=0 ; i<h ; ++i)
for(int j=0 ; j<w ; ++j)
mat[i][j]=0;
m=h;
n=w;
}
matrix friend operator * (matrix a, matrix b)
{
matrix ans(a.m , b.n);
for(int i=0 ; i<ans.m ; ++i)
{
for(int j=0 ; j<ans.n ; ++j)
{
for(int k=0 ; k<a.n ; ++k)
{
ans.mat[i][j]+=a.mat[i][k]*b.mat[k][j];
}
}
}
return ans;
}
};
matrix a(200,200),b(200,1);
int main()
{
int n,m;
while(scanf("%d%d",&n,&m),n||m)
{
a.reset(n,n);
b.reset(n,1);
for(int i=0 ; i<n ; ++i)
{
scanf("%lf",&b.mat[i][0]);
}
int T;
scanf("%d",&T);
double sum[210];
fill(sum,sum+210,1.0);
for(int i=0 ; i<T ; ++i)
{
int x,y;
double p;
scanf("%d%d%lf",&x,&y,&p);
a.mat[y][x]=p;
sum[x]-=p;
}
for(int i=0 ; i<n ; ++i)
{
a.mat[i][i]=sum[i];
}
matrix ans(n,n);
for(int i=0 ; i<n ; ++i)
{
ans.mat[i][i]=1;
}
while(m)
{
if(m&1)
{
ans=ans*a;
}
a=a*a;
m>>=1;
}
b=ans*b;
printf("%.0f\n",b.mat[n-1][0]);
}
return 0;
}