[Jzoj] 1036.【SCOI2009】迷路

题目大意

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

题目解析

由于这道题的 T T T 很大,线性算法是过不了的,所以我们考虑矩阵乘法。
这道题图中的边权为 1   9 1~9 1 9,比较小,所以考虑拆点,为了方便表示,把编号为 i i i的点拆为 i ∗ 10 + 1   i ∗ 10 + 9 i*10+1~i*10+9 i10+1 i10+9 一共 9 9 9 个节点。如果 i i i j j j 有一条权值为 k k k 的路径,那么就把矩阵中 [ i ∗ 10 + k , j ∗ 10 + 1 ] [i*10+k,j*10+1] [i10+k,j10+1]的值设为 1,相当于先从 i ∗ 10 + 1 → i ∗ 10 + k i*10+1→i*10+k i10+1i10+k 走过 k − 1 k-1 k1条长度为 1 1 1 的路径,再在 i ∗ 10 + k → j ∗ 10 + 1 i*10+k→j*10+1 i10+kj10+1 走过 1 1 1 条长度为 1 1 1 的路径,总长度为 k k k,跑一遍快速幂, [ 1 ∗ 10 + 1 ] [ n ∗ 10 + 1 ] [1*10+1][n*10+1] [110+1][n10+1]的值即是方案总数。

代码

#include<bits/stdc++.h>
#define N 105
#define M 2009
using namespace std;
int n,t,an;
int m[N][N],tmp[N][N],ans[N][N];
char c;
void mul(int a[N][N],int b[N][N])
{
	memset(tmp,0,sizeof(tmp));
	for(int i=0;i<an;i++)
	 for(int j=0;j<an;j++)
	  for(int k=0;k<an;k++)
	   tmp[i][j]=(tmp[i][j]+a[i][k]*b[k][j])%M;
	memcpy(a,tmp,sizeof(tmp));
}
void qpow()
{
	for(int i=0;i<an;i++) ans[i][i]=1;
	while(t)
	{
	  if(t&1) mul(ans,m);
	  mul(m,m);
	  t>>=1;
	}
}
int main()
{
	cin>>n>>t;
	an=n*9;
	for(int i=0;i<n;i++)
	{
	  for(int j=0;j<8;j++)
	   m[i*9+j][i*9+j+1]=1;
	  for(int j=0,num;j<n;j++)
	  {
	  	cin>>c;
	  	num=c-'0';
	  	if(num) m[i*9+num-1][j*9]=1;
	  }
	}
	qpow();
	cout<<ans[0][(n-1)*9];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值