输入
3 2
1 2
2 3
2
输出
8
分析:
(通过此题可以进一步了解邻接矩阵相乘的意义)
难点1:邻接矩阵相乘有什么意义?
意义:
a
[
i
]
[
j
]
a[i][j]
a[i][j]: 可乐机器人从
i
i
i到
j
j
j的方案个数
则
a
[
i
]
[
j
]
=
∑
k
=
0
n
(
a
[
i
]
[
k
]
∗
a
[
k
]
[
j
]
)
a[i][j]=\sum_{k=0}^n(a[i][k]*a[k][j])
a[i][j]=∑k=0n(a[i][k]∗a[k][j])表示可乐机器人从
i
i
i到
k
k
k再从
k
k
k到
j
j
j的方案个数
再思考
a
t
a^t
at的意义是什么?(
a
a
a为邻接矩阵;两个点
u
、
v
u、v
u、v之间若有边则
a
[
u
]
[
v
]
=
a
[
u
]
[
v
]
=
1
a[u][v]=a[u][v]=1
a[u][v]=a[u][v]=1)
a t a^t at 的意义: a t a^t at的第 i i i行第 j j j列为从 i i i到 j j j经过 t t t步的路径方案总数。
难点2:停留在原地和自爆怎么通过邻接矩阵表示并一起计算?
原地:可以在初始化邻接矩阵的时候添加
a
[
i
]
[
i
]
=
1
a[i][i]=1
a[i][i]=1表示从i到i有1种方案数;
自爆:可以将此状态也看成一个城市,设为0,添加从
i
i
i到0的边
a
[
i
]
[
0
]
=
1
a[i][0]=1
a[i][0]=1,无出边(即
a
[
0
]
[
i
]
=
0
a[0][i]=0
a[0][i]=0:表示无法从0到别的城市)
代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=2017;
const int N=110;
int n,m,t;
struct jz{
int n,m,a[N][N];
jz(){//初始化
n=m=0;
memset(a,0,sizeof a);
}
};
jz operator * (const jz &x,const jz &y){
jz c;
c.n =x.n ;c.m =y.m ;
for(int i=0;i<=c.n ;i++)
for(int k=0;k<=x.m ;k++)
for(int j=0;j<=c.m ;j++){
c.a[i][j]=(c.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod;
}
return c;
}
jz qpower(jz a,int b){
jz ans;
ans.m =ans.n =n;
for(int i=0;i<=n;i++)ans.a[i][i]=1;
while(b){
if(b&1)ans=ans*a;
a=a*a;
b>>=1;
}
return ans;
}
int main(){
ios::sync_with_stdio(0); cin.tie(0);
cin>>n>>m;
jz x;
x.m =x.n =n;
for(int i=1;i<=m;i++){
int u,v;
cin>>u>>v;
x.a[u][v]=x.a[v][u]=1;
}
for(int i=0;i<=n;i++)x.a[i][i]=1;//原地
for(int i=1;i<=n;i++)x.a[i][0]=1;//自爆
cin>>t;
jz res=qpower(x,t);
int ans=0;
for(int i=0;i<=n;i++)ans=(ans+res.a[1][i])%mod;//统计从1到i的方案数
cout<<ans<<endl;
return 0;
}