baoj1875 HH去散步 【矩陣轉移】

Brief description :

給定一個可能重邊但沒有自環的無向圖,要求計算 A, B 兩點之間步數爲 t 的方案數。答案模 45989。
(可以經過某個點某條邊多次,但是不可以立即沿着同一條邊折返。)
(.. N <= 20, M <= 60, t <= 2^30 ..)

Analyse :

由於“不會沿着同一條邊折返”,因此從 A 點經過 k 步後的狀態僅與最後一步所走的邊和它的方向有關。
如果將每條無向邊拆成兩條有向邊,那麼僅於邊有關。

用 i==(j^1),排除立即走回邊。

比如: 2  0010(u1->v1)                                                    4  0100(u2->v2)

             3  0011(v1->u1)                                                    5  0101(v2->u2)

                    ---->   (2&1)==3  (3&1)==2                                 ----> (4&1)==5  (5&1)==4

友鏈:http://www.shuizilong.com/house/archives/sdoi-2009-hh%E5%8E%BB%E6%95%A3%E6%AD%A5/


CODE:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#include<set>
#define INF 0x7fffffff
#define SUP 0x80000000
#define _p 45989
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;

typedef long long LL;
const int N=100007;

struct Edge{                 //鄰接表節點
    int to,next;
}E[133];
int head[55];
int tot=2;

void add_(int u,int v)
{
    E[tot].to=v;
    E[tot].next=head[u];
    head[u]=tot++;
}

struct Matrix{
    int mat[133][133];
    Matrix()
    {
        mem(mat,0);
    }
    friend Matrix operator *(Matrix a,Matrix b)   //非成員函數重載
    {
        Matrix ans;
        for(int i=1;i<=tot;i++)
        {
            for(int j=1;j<=tot;j++)
            {
                for(int k=1;k<=tot;k++)
                    ans.mat[i][j]+=a.mat[i][k]*b.mat[k][j]%_p,ans.mat[i][j]%=_p;
            }

        }
        return ans;
    }

    friend Matrix operator^(Matrix a,int b)
    {
        Matrix ans;
        for(int i=1;i<=tot;i++) ans.mat[i][i]=1;
        while(b)
        {
            if(b&1) ans=ans*a;    //出去回邊
            a=a*a;
            b>>=1;
        }
        return ans;
    }
};




int main()
{
    int n,m,t,a,b;
    while(scanf("%d%d%d%d%d",&n,&m,&t,&a,&b)==5)
    {
        mem(head,-1);
        int u,v;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&u,&v);
            add_(u,v);
            add_(v,u);
        }

        Matrix st,tt;
        for(int i=head[a];i!=-1;i=E[i].next) st.mat[1][i]=1;   //初始的一步

        vector<int> en;
        for(int i=2;i<tot;i++)    //轉移的矩陣
        {
            int to=E[i].to;
            if(to==b) en.push_back(i);
            for(int j=head[to];j!=-1;j=E[j].next)  
            {
                if(i==(j^1)) continue;
                tt.mat[i][j]=1;
            }
        }

        int ans=0;
        st=st*(tt^(t-1));       // 1+(t-1)==t步  ,即初始一步+轉移t-1次
        for(int i=0;i<en.size();i++)
        {
            ans=(ans+st.mat[1][en[i]])%_p;
        }
        printf("%d\n",ans);
    }


    return 0;
}



發佈了149 篇原創文章 · 獲贊 16 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章