Educational DP Contest R - Walk(倍增floyd)
R - Walk
原题链接:https://atcoder.jp/contests/dp/tasks/dp_r
题目大意:
给一个有向图,求经过k条边的路径个数(允许重复)。
解题思路:
倍增folyd算法,求解一个图中经过k条边的路径最大距离或最小距离或经过k条边的路径有多少个时要用到,也叫做矩阵乘法。首先,我们有两个矩阵,如果其中一个矩阵代表恰好经过x条边的最短路,另外一个矩阵代表恰好经过y条边的最短路。那么将这两个矩阵合并就代表恰好经过x+y条边的最短路。
本题给出的二维矩阵就是经过一条边的所有路径个数,然后利用快速幂与矩阵相乘求出经过k条边的路径。
代码:
1 #include <bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 #define debug(a) cout<<#a<<":"<<a<<endl;
5 const ll INF=0x3f3f3f3f;
6 const ll N=1e6+7;
7 const ll mod=1e9+7;
8 ll maxn,minn;
9 ll T,n,m,k;
10
11 ll f;
12 struct node{
13 ll arr[100][100];
14 };
15
16 node mul(node x,node y){
17 node ans;
18 memset(ans.arr,0,sizeof(ans.arr));
19 for(ll k = 1;k<=n;k++){
20 for(ll i = 1;i<=n;i++){
21 for(ll j = 1;j<=n;j++){
22 ans.arr[i][j] = (ans.arr[i][j]+(x.arr[i][k]*y.arr[k][j])%mod)%mod;
23 }
24 }
25 }
26 return ans;
27 }
28 node ksm(node a,ll b){
29 node ans;
30 memset(ans.arr,0,sizeof(ans.arr));
31 for(ll i=1;i<=f;i++)
32 ans.arr[i][i]=1;
33 while(b){
34 if(b&1) ans=mul(ans,a);
35 a=mul(a,a); b>>=1;
36 }
37 return ans;
38 }
39
40
41 int main(){
42 ll ans=0;
43 node x,y;
44 cin>>n>>k;
45 f=n;
46 for(ll i=1;i<=n;i++){
47 for(ll j=1;j<=n;j++){
48 scanf("%lld",&x.arr[i][j]);
49 }
50 }
51 y=ksm(x,k);
52 for(ll i=1;i<=n;i++){
53 for(ll j=1;j<=n;j++){
54 ans=(ans+y.arr[i][j])%mod;
55 }
56 }
57 cout<<ans<<endl;
58 return 0;
59 }