Brief description :
給定一個可能重邊但沒有自環的無向圖,要求計算 A, B 兩點之間步數爲 t 的方案數。答案模 45989。
(可以經過某個點某條邊多次,但是不可以立即沿着同一條邊折返。)
(.. N <= 20, M <= 60, t <= 2^30 ..)
Analyse :
由於“不會沿着同一條邊折返”,因此從 A 點經過 k 步後的狀態僅與最後一步所走的邊和它的方向有關。
如果將每條無向邊拆成兩條有向邊,那麼僅於邊有關。
用 i==(j^1),排除立即走回邊。
比如: 2 0010(u1->v1) 4 0100(u2->v2)
3 0011(v1->u1) 5 0101(v2->u2)
----> (2&1)==3 (3&1)==2 ----> (4&1)==5 (5&1)==4
友鏈:http://www.shuizilong.com/house/archives/sdoi-2009-hh%E5%8E%BB%E6%95%A3%E6%AD%A5/
CODE:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#define INF 0x7fffffff
#define SUP 0x80000000
#define _p 45989
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long LL;
const int N=100007;
struct Edge{ //鄰接表節點
int to,next;
}E[133];
int head[55];
int tot=2;
void add_(int u,int v)
{
E[tot].to=v;
E[tot].next=head[u];
head[u]=tot++;
}
struct Matrix{
int mat[133][133];
Matrix()
{
mem(mat,0);
}
friend Matrix operator *(Matrix a,Matrix b) //非成員函數重載
{
Matrix ans;
for(int i=1;i<=tot;i++)
{
for(int j=1;j<=tot;j++)
{
for(int k=1;k<=tot;k++)
ans.mat[i][j]+=a.mat[i][k]*b.mat[k][j]%_p,ans.mat[i][j]%=_p;
}
}
return ans;
}
friend Matrix operator^(Matrix a,int b)
{
Matrix ans;
for(int i=1;i<=tot;i++) ans.mat[i][i]=1;
while(b)
{
if(b&1) ans=ans*a; //出去回邊
a=a*a;
b>>=1;
}
return ans;
}
};
int main()
{
int n,m,t,a,b;
while(scanf("%d%d%d%d%d",&n,&m,&t,&a,&b)==5)
{
mem(head,-1);
int u,v;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&u,&v);
add_(u,v);
add_(v,u);
}
Matrix st,tt;
for(int i=head[a];i!=-1;i=E[i].next) st.mat[1][i]=1; //初始的一步
vector<int> en;
for(int i=2;i<tot;i++) //轉移的矩陣
{
int to=E[i].to;
if(to==b) en.push_back(i);
for(int j=head[to];j!=-1;j=E[j].next)
{
if(i==(j^1)) continue;
tt.mat[i][j]=1;
}
}
int ans=0;
st=st*(tt^(t-1)); // 1+(t-1)==t步 ,即初始一步+轉移t-1次
for(int i=0;i<en.size();i++)
{
ans=(ans+st.mat[1][en[i]])%_p;
}
printf("%d\n",ans);
}
return 0;
}