[YZOJ]P1397-奔跑的骑士-矩阵建模

来源:互联网 发布:笔记本电脑必备软件 编辑:程序博客网 时间:2024/05/24 07:16

链接

题意描述:
给定一张无向图,一个起点一个终点。
定义一条合法路径为不存在任何一条满足A->B->A的关系的子路径。
求从起点到终点长为一个值的路径数。

数据范围:
对于30%的数据,N ≤ 4,M ≤ 10,t ≤ 10。
对于100%的数据,N ≤ 20,M ≤ 60,t ≤ 2147483647,0 ≤ A,B<=N-1。

解法:
30分做法:用队列维护走过当前长度到达的点,拓展转移可行转移。当长度达到定值的时候,若达到终点,则答案加一。
复杂度:最劣O(nt)

100分做法:
由于转移次数较多,很自然的想到可以利用矩阵表示转移,用快速幂进行优化。

问题在于,如何用一个矩阵表示一系列转移?
用一个数列表示当前走到每个点的方案数。这些数在一步操作后会发生复杂的转移,累加到其他格子里面去,这正是矩阵所支持的。
若没有合法路径的限制?
最直观的想法是,在矩阵中,一行表示当前点被转移的来源。若存在j->i的路径,则ai,j=1
这样乘上一个矩阵就表示进行了一次全部的转移。

如果加上路径的限制条件呢?
相当于只能“向前走”。可惜,点是不具有方向性的,所以我们把转移对象选择为边。边可以分成两条,分别为u->v和v->u,而按照这个想法,如果存在v->k,则边u->v可以向v->k转移。按照这个想法我们就重新建立了一个合法的矩阵。

#include<cstdio>#include<algorithm>#include<cstring>#define R register#define mod 45989#define ll long longusing namespace std;struct new_node{int a,b;}node[125];int n,m,kk,A,B;int nt;int bs[125];int read(){    R int xx;R char ch;    while(ch=getchar(),ch<'0'||ch>'9');xx=ch-'0';    while(ch=getchar(),ch>='0'&&ch<='9')xx=xx*10+ch-'0';    return xx;}struct MAT{    int a[123][123];    inline MAT operator * (const MAT &f)const    {        R MAT ret;        R int i,j,k;        for(i=0;i<=nt;++i)            for(j=0;j<=nt;++j)            {                ret.a[i][j]=0;                for(k=0;k<=nt;++k)                    ret.a[i][j]=(ret.a[i][j]+a[i][k]*f.a[k][j])%mod;            }        return ret;    }       }v0,v1,ans;void pow(int k){    R MAT base=v1;    ans=v0;    while(k)    {        if(k&1)ans=ans*base;        base=base*base;k>>=1;    }}void build(){    R int i,j,x,y;    memset(v0.a,0,sizeof(v0.a));    memset(v1.a,0,sizeof(v1.a));    memset(bs,0,sizeof(bs));    nt=-1;    for(i=1;i<=m;++i)    {        x=read(),y=read();        node[++nt]=(new_node){x,y};        node[++nt]=(new_node){y,x};    }    for(i=0;i<=nt;++i)    {        for(j=0;j<=nt;++j)        {            if(node[i].a==node[j].b&&i!=(j^1))            v1.a[i][j]=1;        }    }    for(i=0;i<=nt;++i)v0.a[i][i]=1;}void print(){    int sum=0;    R int i,e;    for(i=0;i<=nt;++i)        if(node[i].a==A)            bs[i]=1;    for(e=0;e<=nt;++e)        if(node[e].b==B)        {            for(i=0;i<=nt;++i)                sum=(sum+(ll)bs[i]*ans.a[e][i])%mod;        }    printf("%d",sum);}int main(){    n=read(),m=read(),kk=read(),A=read(),B=read();    build();pow(kk-1);print();    return 0;}/*      void show()    {        printf("begin:\n");        R int i,j;        for(i=0;i<=nt;++i,printf("\n"))            for(j=0;j<=nt;++j)                printf("%d ",a[i][j]);        printf("end\n");    }   */
原创粉丝点击