题目大意:给出一张无向图,求从A到B走k步(不能走回头路)的方案数。(k <= 2^30)
思路:看到k的范围就知道是矩阵乘法了。关键是不能走回头路怎么构造。正常的方法构造点的转移不能避免这个问题,就用边来构造。只要保证不经过自己^1的边就可以保证不走回头路了。
CODE:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 210
#define MO 45989
using namespace std;
int total = 1;
struct Matrix{
int num[MAX][MAX];
Matrix() {
memset(num,0,sizeof(num));
}
Matrix operator *(const Matrix &a)const {
Matrix re;
for(int i = 0; i <= total; ++i)
for(int j = 0; j <= total; ++j)
for(int k = 0; k <= total; ++k) {
re.num[i][j] += num[i][k] * a.num[k][j];
re.num[i][j] %= MO;
}
return re;
}
}src,ans,temp;
int points,edges,t;
int S,T;
int head[MAX];
int next[MAX],aim[MAX];
inline void Add(int x,int y)
{
next[++total] = head[x];
aim[total] = y;
head[x] = total;
}
int stack[MAX],top;
int main()
{
cin >> points >> edges >> t >> S >> T;
++S,++T;
for(int x,y,i = 1; i <= edges; ++i) {
scanf("%d%d",&x,&y);
x++,y++;
Add(x,y),Add(y,x);
}
for(int i = head[S]; i; i = next[i])
ans.num[0][i] = 1;
for(int i = 2; i <= total; ++i) {
int x = aim[i];
if(x == T) stack[++top] = i;
for(int j = head[x]; j; j = next[j]) {
if(j == (i^1)) continue;
src.num[i][j] = 1;
}
}
for(int i = 0; i <= total; ++i) temp.num[i][i] = 1;
--t;
while(t) {
if(t&1) temp = temp * src;
src = src * src;
t >>= 1;
}
ans = ans * temp;
int p = 0;
for(int i = 1; i <= top; ++i)
p = (p + ans.num[0][stack[i]]) % MO;
cout << p << endl;
return 0;
}