【codevs2304】【BZOJ1875】HH去散步,第一次的矩阵加速DP

传送门1
传送门2
写在前面:今天冒傻气
思路:我第一眼没有看出来它是个矩阵乘法加速DP,只觉得如果这个t小点就直接广搜可以了,后来发现网上的题解无一例外都是矩阵快速幂的时候,我的表情
【codevs2304】【BZOJ1875】HH去散步,第一次的矩阵加速DP_第1张图片
后来看了看黄学长的题解,才想到是可以利用矩阵乘法的性质进行快速幂的,但是之前并没有做过矩阵加速DP的题目= =这里按照我的理解简单说一下吧
1.先是建邻接表,无向图建双向,其实可以从0或2为起始边开始的,因为这样做求反向边时直接^运算就可以了,但我这里是1建边,所以写了个函数,比较麻烦
2.b是转移矩阵,b.map[i][j]代表在某种情况下第i条路到第j条路的走法总数,而且要排除对于同一条路连续两次来回走的情况,连续转移length-1次(因为有一次要给从起点出发)
3.a是起始矩阵,实际上就是从起点出来到各个边的终点上去,a*b后所谓的a.map[1][i]就是从起点最终到达road[i].son的方法总数,然后就可以随便搞了
代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mod 45989
#define LL long long
using namespace std;
int n,m,s,t,tot,length,ans;
int first[61];
struct os
{
    int fa,son,next;
}road[130];
struct matrix
{
    int map[130][130];
}a,b;
int zh(int x)
{
    if (x&1) return x+1;
    return x-1;
}
void add(int x,int y)
{
    road[++tot].fa=x;
    road[tot].son=y;
    road[tot].next=first[x];
    first[x]=tot;
}
matrix mul(matrix a,matrix b)
{
    matrix c;
    memset(c.map,0,sizeof(c.map));
    for (int i=1;i<=tot;i++)
    for (int j=1;j<=tot;j++)
    for (int k=1;k<=tot;k++)
    c.map[i][j]=(c.map[i][j]+(a.map[i][k]*b.map[k][j]%mod))%mod;
    return c;
}
matrix qr(matrix a,int b)
{
    matrix c;
    c=a;
    b--;
    while (b)
    {
        if (b&1) c=mul(c,a);
        a=mul(a,a);
        b>>=1;
    }
    return c;
}
main()
{
    scanf("%d%d%d%d%d",&n,&m,&length,&s,&t);
    int x,y;
    for (int i=1;i<=m;i++)
    scanf("%d%d",&x,&y),
    add(x,y),
    add(y,x);
    for (int i=1;i<=tot;i++)
    for (int j=1;j<=tot;j++)
    if (road[i].son==road[j].fa&&j!=zh(i)) j!=zh(i)排除对于同一条路连续两次来回走的情况
    b.map[i][j]++;
    b=qr(b,length-1);

    for (int i=first[s];i;i=road[i].next)
    a.map[1][i]++;
    a=mul(a,b);
    for (int i=first[t];i;i=road[i].next)
    ans=(ans+a.map[1][zh(i)])%mod;//zh(i)得到以a[i].son=t的边
    printf("%d",ans);
}

你可能感兴趣的:(【codevs2304】【BZOJ1875】HH去散步,第一次的矩阵加速DP)