BZOJ1297 [SCOI2009]迷路 矩阵乘法

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ1297


题意概括

  有向图有 N 个节点,从节点 0 出发,他必须恰好在 T 时刻到达节点 N-1。 现在给出该有向图,问总共有多少种不同的路径吗? 注意:不能在某个节点逗留,且通过某有向边的时间严格为给定的时间。


题解

  矩阵乘法。

  把一个点拆成9个,分别是time+0,time+1,time+2,...,time+8。

  然后根据输入转移,构建矩阵即可。

  然后基础矩阵跑一跑就可以了。


插曲

  悲催,一个小错找了1个小时:

  把设置单位矩阵打成这样了……

  


代码

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=10+5,maxm=N*10,mod=2009;
int n,m,t;
char str[N][N];
struct Mat{
	int v[maxm][maxm];
	void set(){
		memset(v,0,sizeof v);
	}
	void set1(){
		set();
		for (int i=0;i<m;i++)
			v[i][i]=1;
	}
	Mat operator * (Mat a){
		Mat ans;
		ans.set();
		for (int i=0;i<m;i++)
			for (int j=0;j<m;j++)
				for (int k=0;k<m;k++)
					ans.v[i][j]=(ans.v[i][j]+v[i][k]*a.v[k][j])%mod;
		return ans;
	}
}M,Mans;
Mat MatPow(Mat x,int y){
	Mat M,xx=x;
	M.set1();
	while (y){
		if (y&1)
			M=M*xx;
		xx=xx*xx;
		y>>=1;
	}
	return M;
}
int Hash(int x,int y){
	return x*9+y;
}
int main(){
	scanf("%d%d",&n,&t);
	m=n*9;
	for (int i=0;i<n;i++)
		scanf("%s",str[i]);
	M.set();
	for (int i=0;i<n;i++)
		for (int j=0;j<8;j++)
			M.v[Hash(i,j+1)][Hash(i,j)]++;
	for (int i=0;i<n;i++)
		for (int j=0;j<n;j++)
			if (str[i][j]!='0')
				M.v[Hash(i,0)][Hash(j,str[i][j]-'1')]++;
	Mans=MatPow(M,t);
	printf("%d",Mans.v[0][Hash(n-1,0)]);
	return 0;
}

  

posted @ 2017-08-26 12:53  zzd233  阅读(283)  评论(0编辑  收藏  举报