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]\),正好满足矩阵运算的规则。
之前一直没有证明矩阵快速幂的正确性,要证明这个,只需要证明它满足结合律就行。

首先我们证明 [公式]

[公式][公式] 的矩阵, [公式] [公式]

[公式]

[公式]

所以 [公式] ,即 [公式]

现在进行归纳证明,假设在 [公式] 时对 [公式] 个矩阵相乘满足结合律,证明在 [公式] 时也满足结合律

我们现在试图证明对任意顺序做乘法的 [公式] ,都与 [公式] 相等

考虑任意顺序做乘法的矩阵,找到最后一次相乘的乘号(即没有被任何一个括号包含的乘号),考虑这个乘号两边的矩阵,不妨设左边共有 [公式] 个矩阵,右边共有 [公式] 个矩阵,那么由于 [公式] ,所以 [公式] ,所以根据归纳假设,左边可以写成 [公式] ,右边可以写成 [公式]

然后,因为我们知道了 [公式] 满足结合律,我们可以将 [公式] 写成 [公式] 的形式,然后一层一层将右侧的括号拆掉即可

所以任意顺序相乘的 [公式] 都相等,等于 [公式]

现在证明出了对于 [公式] 时结合律也成立,所以对任意 [公式][公式] 个矩阵相乘符合结合律。

证毕。

我相信现在你对矩阵快速幂已经熟能生巧了

posted @ 2020-05-17 22:15  An_Fly  阅读(185)  评论(0编辑  收藏  举报