【BZOJ】1875: [SDOI2009]HH去散步 矩阵快速幂

【题意】给定n个点m边的无向图,求A到B恰好经过t条边的路径数,路径须满足每条边都和前一条边不同。n<=20,m<=60,t<=2^30。

【算法】矩阵快速幂

【题解】将图的邻接矩阵进行矩阵快速幂就可以得到恰好经过t条边的路径数,但不能满足题目要求。

改为对原图的边进行相互连边,将经过同一个点的边两两连边,这样就是新邻接矩阵的t-1步。

为了满足题目要求,当两条边互为反向边时不连边即可。

最后乘上从A出发的边的矩阵,然后统计到达B的路径数。

复杂度O((m*2)^3 log t)。

#include<cstdio>
#include<cstring>
const int maxn=130,MOD=45989;
int n,m,t,A,B,a[maxn][maxn],ans[maxn][maxn],c[maxn][maxn],tot=1,first[maxn];
struct edge{int v,from;}e[maxn];
 
void multply(int a[maxn][maxn],int b[maxn][maxn]){
    for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)c[i][j]=0;
    for(int i=1;i<=n;i++)
        for(int k=1;k<=n;k++)
            for(int j=1;j<=n;j++)c[i][j]=(c[i][j]+a[i][k]*b[k][j])%MOD;
    for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)a[i][j]=c[i][j];
}
void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
int main(){
    scanf("%d%d%d%d%d",&n,&m,&t,&A,&B);A++;B++;
    for(int i=1;i<=m;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        insert(++u,++v);insert(v,u);
    }
    for(int i=2;i<=tot;i++){
        for(int j=first[e[i].v];j;j=e[j].from)if(i!=(j^1)){
            a[i][j]++;
        }
    }
    for(int i=first[A];i;i=e[i].from)a[1][i]++;//
    n=tot;
    for(int i=1;i<=n;i++)ans[i][i]=1;
    while(t){
        if(t&1)multply(ans,a);
        multply(a,a);
        t>>=1;
    }
    int ANS=0;
    for(int i=first[B];i;i=e[i].from)ANS=(ANS+ans[1][i^1])%MOD;
    printf("%d",ANS);
    return 0;
}
View Code

 

posted @ 2018-03-01 09:40  ONION_CYC  阅读(...)  评论(...编辑  收藏