1875. [SDOI2009]HH去散步【矩阵乘法】

Description

HH有个一成不变的习惯,喜欢饭后百步走。所谓百步走,就是散步,就是在一定的时间 内,走过一定的距离。 但
是同时HH又是个喜欢变化的人,所以他不会立刻沿着刚刚走来的路走回。 又因为HH是个喜欢变化的人,所以他每
天走过的路径都不完全一样,他想知道他究竟有多 少种散步的方法。 现在给你学校的地图(假设每条路的长度都
是一样的都是1),问长度为t,从给定地 点A走到给定地点B共有多少条符合条件的路径

Input

第一行:五个整数N,M,t,A,B。
N表示学校里的路口的个数
M表示学校里的 路的条数
t表示HH想要散步的距离
A表示散步的出发点
B则表示散步的终点。
接下来M行
每行一组Ai,Bi,表示从路口Ai到路口Bi有一条路。
数据保证Ai != Bi,但不保证任意两个路口之间至多只有一条路相连接。 
路口编号从0到N -1。 
同一行内所有数据均由一个空格隔开,行首行尾没有多余空格。没有多余空行。 
答案模45989。
N ≤ 20,M ≤ 60,t ≤ 2^30,0 ≤ A,B

Output

一行,表示答案。

Sample Input

4 5 3 0 0
0 1
0 2
0 3
2 1
3 2

Sample Output

4

第一道矩阵乘法……orz调了半天发现自己犯了一个傻逼错误
多余的不解释了,学习笔记里有思路。

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #define MOD (45989)
 6 using namespace std;
 7 struct Mar
 8 {
 9     int a[201][201];
10 } unit,G;
11 struct node1
12 {
13     int to,next;
14 } edge[10001];
15 int n,head[10001],num_edge;
16 
17 void add(int u,int v)
18 {
19     edge[num_edge].to=v;
20     edge[num_edge].next=head[u];
21     head[u]=num_edge++;
22 }
23 
24 Mar Mul(Mar x,Mar y)
25 {
26     Mar c;
27     memset(c.a,0,sizeof(c.a));//初始化,不然会GG 
28     for (int i=0; i<=num_edge-1; ++i)
29         for (int j=0; j<=num_edge-1; ++j)
30             for (int k=0; k<=num_edge-1; ++k)
31                 c.a[i][j]=(c.a[i][j]+x.a[i][k]*y.a[k][j])%MOD;
32     return c;
33 }
34 
35 Mar Mar_pow(Mar a,int p)
36 {
37     Mar ans=unit;
38     while (p!=0)
39     {
40         if (p&1)
41             ans=Mul(ans,a);
42         a=Mul(a,a);
43         p>>=1;
44     }
45     return ans;
46 }
47 
48 int main()
49 {
50     int m,t,st,ed,u,v;
51     scanf("%d%d%d%d%d",&n,&m,&t,&st,&ed);
52     ++st;++ed;
53     for (int i=1; i<=n; ++i) head[i]=-1;
54     for (int i=1; i<=m; ++i)
55     {
56         scanf("%d%d",&u,&v);
57         ++u;++v;
58         add(u,v);add(v,u);
59     }
60     for (int i=0; i<=num_edge-1; ++i)
61         unit.a[i][i]=1;//给单位矩阵赋值 
62     for (int i=0; i<=num_edge-1; ++i)
63         for (int j=head[edge[i].to]; j!=-1; j=edge[j].next)
64             if ((i!=(j^1)))
65                 G.a[i][j]++;
66     
67     G=Mar_pow(G,t-1);
68     int Final=0;
69     for (int i=head[st]; i!=-1; i=edge[i].next)
70         for (int j=head[ed]; j!=-1; j=edge[j].next)
71             Final=(Final+G.a[i][j^1])%MOD;//异或就是将二进制最后一位取反,即入边变出边,出边变入边 
72     printf("%d",Final);
73 }
posted @ 2018-03-30 21:06  Refun  阅读(173)  评论(0编辑  收藏  举报