bzoj 1297: [SCOI2009]迷路(矩阵快速幂)

1297: [SCOI2009]迷路

Time Limit: 10 Sec   Memory Limit: 162 MB
Submit: 1322   Solved: 938
[ Submit][ Status][ Discuss]

Description

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

Input

第一行包含两个整数,N T。 接下来有 N 行,每行一个长度为 N 的字符串。 第i行第j列为'0'表示从节点i到节点j没有边。 为'1'到'9'表示从节点i到节点j需要耗费的时间。

Output

包含一个整数,可能的路径数,这个数可能很大,只需输出这个数除以2009的余数。

Sample Input

2 2
11
00
5 30
12045
07105
47805
12024
12345

Sample Output

1
852


性质:如果一张图的邻接矩阵只有0和1表示通与不通的话,

从s到t且中间经过n条边的方案数就是这个矩阵自乘n次后的(s, t)的数值

这题的边长度范围是0到9

那么只要将每个点拆成9个点就好了

首先这九个点连成一条直线(第j个点和第j+1个点连边)

如果点x到点y有条长度为k的边,那么x的第k个点和y的第一个点连条边就好

之后就直接矩阵快速幂


#include<stdio.h>
#include<string.h>
#define mod 2009
typedef struct
{
	int i, a[105][105];
	void init(int n)
	{
		memset(a, 0, sizeof(a));
		for(i=1;i<=n;i++)
			a[i][i] = 1;
	}
}Matrix;
Matrix Jz;
int n, m;
Matrix Jzcf(Matrix p1, Matrix p2)
{
	Matrix pe;
	int i, j, k;
	memset(pe.a, 0, sizeof(pe.a));
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=n;j++)
		{
			for(k=1;k<=n;k++)
				pe.a[i][j] = (pe.a[i][j]+p1.a[i][k]*p2.a[k][j])%mod;
		}
	}
	return pe;
}
Matrix Powto(Matrix x, int y)
{
	Matrix ans;
	ans.init(n);
	while(y)
	{
		if(y%2==1)
			ans = Jzcf(ans, x);
		x = Jzcf(x, x);
		y /= 2;
	}
	return ans;
}
int main(void)
{
	int i, j, x;
	while(scanf("%d%d", &n, &m)!=EOF)
	{
		memset(Jz.a, 0, sizeof(Jz.a));
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=8;j++)
				Jz.a[(i-1)*9+j][(i-1)*9+j+1] = 1;
		}
		for(i=1;i<=n;i++)
		{
			for(j=1;j<=n;j++)
			{
				scanf("%1d", &x);
				if(x==0)
					continue;
				Jz.a[(i-1)*9+x][(j-1)*9+1] = 1;
			}
		}
		n = n*9;
		Jz = Powto(Jz, m);
		printf("%d\n", Jz.a[1][n-8]);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值