题目描述
题解
对于读进来的两个点x,y,x->y,y->x;
对于三个点x,y,z,如果存在边i使x->y,边j使y->z,那么在邻接矩阵G里将(i,j)赋为1.
求
Gt−1
即可.
解释一下,这里将一条双向边拆成两条单向边,并且只有连续的连边关系才能在邻接矩阵里标记,目的是不能走回头路.
构造好邻接矩阵之后,相当于构造出了一个新的图,这个图里的点相当于是原图里的一条边,那么在原图里恰好要经过t条边,在新的图里就要经过t个点,即t-1条边.并且这样的建图方式保证在新图里也不会走回头路,因为两条边不可能互相连边。
感觉这个思路很厉害呀。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int max_n=25;
const int max_m=65;
const int max_N=max_m*2;
const int max_M=max_N*max_N;
const int max_e=max_M*2;
const int Mod=45989;
int n,m,t,st,end,x,y,final;
int tot,point[max_N],nxt[max_e],v[max_e];
struct hp{int a[max_N][max_N];}G,unit,ans;
inline void addedge(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
inline hp cheng(hp a,hp b)
{
hp ans;
memset(ans.a,0,sizeof(ans.a));
for (int i=0;i<=tot;++i)
for (int j=0;j<=tot;++j)
for (int k=0;k<=tot;++k)
ans.a[i][j]=(ans.a[i][j]+a.a[i][k]*b.a[k][j]%Mod)%Mod;
return ans;
}
inline hp matrix_fast_pow(hp a,int p)
{
hp ans=unit;
for (;p;p>>=1,a=cheng(a,a))
if (p&1)
ans=cheng(ans,a);
return ans;
}
int main()
{
scanf("%d%d%d%d%d",&n,&m,&t,&st,&end);
st++; end++;
tot=-1; memset(point,-1,sizeof(point)); memset(nxt,-1,sizeof(nxt));
for (int i=1;i<=m;++i)
{
scanf("%d%d",&x,&y); x++; y++;
addedge(x,y);
}
for (int i=0;i<=tot;++i) unit.a[i][i]=1;
for (int i=0;i<=tot;++i)
for (int j=point[v[i]];j!=-1;j=nxt[j])
if (i!=(j^1))
G.a[i][j]++;
ans=matrix_fast_pow(G,t-1);
for (int i=point[st];i!=-1;i=nxt[i])
for (int j=point[end];j!=-1;j=nxt[j])
final=(final+ans.a[i][j^1])%Mod;
printf("%d\n",final);
}
总结
首先这道题新学到的思想:化边为点,双向边拆两条单向边。