How many ways?? 矩阵
分析
这个题又是特殊的最短路问题
等等再说矩阵的问题,因为这个题的范围比较小,所以。。。可以写一个计数DP来解决。
估计看一眼代码就可以明白了。
#include<cstdio>
#include<cstring>
#include<algorithm>
const int N=1e2+10;
int dis[N][N],to[N][N];
int main(){
int n,m;
while(~scanf("%d%d",&n,&m)){
if(n==0&&m==0)return 0;
memset(to,0,sizeof(to));
for(int i=1;i<=m;i++){
int a,b;
scanf("%d%d",&a,&b);
to[a][b]=1;
}
int T;
scanf("%d",&T);
while(T--){
int a,b,k;
memset(dis,0,sizeof(dis));
scanf("%d%d%d",&a,&b,&k);
dis[0][a]=1;
for(int x=1;x<=k;x++){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(to[i][j])
dis[x][j]=(dis[x][j]+dis[x-1][i])%1000;
}
}
}
printf("%d\n",dis[k][b]);
}
}
}
因为时间复杂度的问题,所以这个跑起来比矩阵还要快。
但是如果把\(k\)的范围调大而\(n\)的范围不变,这样就会T,\(k\)是想多大就多大的,因为点可以重复经过,所以这题又被数据坑了?
矩阵的题也写过很多次了,敏感的话可以直接写出答案就是\(A^k\)这个矩阵中对应的点的值。
可以这么考虑,如果有\(dis[i][k]=a,dis[k][j]=b,i->k,k->j\)均只走了一步,那么根据分步乘法,走两步时\(dis[i][j]+=dis[i][k]×dis[k][j]\),正好满足矩阵运算的规则。
之前一直没有证明矩阵快速幂的正确性,要证明这个,只需要证明它满足结合律就行。
首先我们证明
设 为 的矩阵,
则
所以 ,即
现在进行归纳证明,假设在 时对 个矩阵相乘满足结合律,证明在 时也满足结合律
我们现在试图证明对任意顺序做乘法的 ,都与 相等
考虑任意顺序做乘法的矩阵,找到最后一次相乘的乘号(即没有被任何一个括号包含的乘号),考虑这个乘号两边的矩阵,不妨设左边共有 个矩阵,右边共有 个矩阵,那么由于 ,所以 ,所以根据归纳假设,左边可以写成 ,右边可以写成
然后,因为我们知道了 满足结合律,我们可以将 写成 的形式,然后一层一层将右侧的括号拆掉即可
所以任意顺序相乘的 都相等,等于
现在证明出了对于 时结合律也成立,所以对任意 , 个矩阵相乘符合结合律。
证毕。我相信现在你对矩阵快速幂已经熟能生巧了
int - > long long
0 - > 100