sdoi 2009 HH去散步 矩阵乘

如果没有题里的“不会立刻沿着刚刚走来的路走回”限制,那么直接矩乘计算k步的方案数

但加了这个限制,就不能以点来矩乘了,考虑边数<=60,如果以边建邻接矩阵呢??

先拆边,再把每一个边和以其终点为起点的边相连,注意不能是拆前的同一条边。

然后矩阵乘喽。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mod 45989
using namespace std;
int a[122][122],b[122],c[122][122],d[122];
int ans,n,m,t,S,T;
bool bo;
int e=1,head[22];
struct edge{
    int u,v,next;
}ed[122];
void add(int u,int v){
    ed[e].u=u; ed[e].v=v;
    ed[e].next=head[u];
    head[u]=e++;
}
void work(int A[122][122],int B[122][122],int C[122][122]){
    int D[122][122];
    for(int i=1;i<=2*m;i++)
        for(int j=1;j<=2*m;j++){
            D[i][j]=0;
            for(int k=1;k<=2*m;k++)
              D[i][j]=(D[i][j]+(A[i][k]*B[k][j])%mod)%mod;
        }
    for(int i=1;i<=2*m;i++)
        for(int j=1;j<=2*m;j++)
            C[i][j]=D[i][j];
}
int main()
{
    int u,v;
    scanf("%d%d%d%d%d",&n,&m,&t,&S,&T); S++; T++;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&u,&v);
        u++; v++;
        add(u,v); add(v,u);
    }
    for(int i=1;i<=2*m;i++)
        for(int j=1;j<=2*m;j++){
            if(ed[i].v==ed[j].u) 
                a[i][j]=1;
        }
    for(int i=1;i<=2*m;i+=2) a[i][i+1]=a[i+1][i]=0;
    for(int i=1;i<=2*m;i++) c[i][i]=1;
     
    for(int i=head[S];i;i=ed[i].next) b[i]=1;
    t--;
     
    while(t){
        if(t&1) work(a,c,c);
        work(a,a,a);
        t>>=1;
    }
     
    for(int i=1;i<=2*m;i++)
        for(int j=1;j<=2*m;j++)
            d[i]=(d[i]+(b[j]*c[j][i])%mod)%mod;
             
    for(int i=1;i<=2*m;i++)
        if(ed[i].v==T)  ans=(ans+d[i])%mod;
    printf("%d\n",ans);
    return 0;
}



posted @ 2017-07-13 21:35  Ren_Ivan  阅读(152)  评论(0编辑  收藏  举报