[BZOJ1875] [SDOI2009] HH去散步

本文介绍了一种处理无向图的算法实现,通过将边视为节点建立邻接矩阵来解决路径问题。该方法避免重复使用相同的边,并通过矩阵运算高效地计算从起点到终点的可达路径数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个还是想了很久 第一次见这种把边看成点的邻接矩阵 

由于是无向图 两条边会一起加 第i条边过后你就不能使用第i ^ 1条边了

提前记录连接起点和终点的边即可

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXM = 120;
const int MAXN = 20;
const int p = 45989;
struct Matrix {
    int n, m;
    int A[MAXM+10][MAXM+10];
}Map, E, Z, MAP;
typedef pair<int, int> pii;
pii Edge[MAXM+10];
int n, m, K, st, ed, ecnt, N;
int EI[MAXN+10], EO[MAXN+10], In, Out;
void GET_E()
{
    E.n = E.m = N;
    for(int i = 0; i < N; i++)
        E.A[i][i] = 1;
}
Matrix mul(Matrix A, Matrix B) {
    Matrix D;
    D.n = A.n;
    D.m = A.m;
    memset(D.A, 0, sizeof(D.A));
    for (int i = 0; i < D.n; i++) {
        for (int j = 0; j < D.m; j++) {
            for (int k = 0; k < A.m; k++) {
                D.A[i][j] += A.A[i][k] * B.A[k][j];
                D.A[i][j] %= p;
            }
        }
    }
    return D;
}
Matrix pow_mod(Matrix &A, int k)  
{  
    Matrix ans = E, t = A;  
    ans.n = A.n;  
    ans.m = A.m;  
    while(k)  
    {  
        if(k & 1)  
            ans = mul(ans, t); 
        t = mul(t, t);  
        k >>= 1;  
    }  
    return ans;  
}  
int main()
{
    scanf("%d%d%d%d%d", &n, &m, &K, &st, &ed);
    for(int i = 0; i < m; i++)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        Edge[ecnt++] = make_pair(u, v);
        Edge[ecnt++] = make_pair(v, u);
    }
    N = ecnt;
    Matrix ANS;
    for(int i = 0; i < N; i++)
    {
        if(Edge[i].first == st) EI[In++] = i;
        if(Edge[i].second == ed) EO[Out++] = i;
        for(int j = 0; j < N; j++)
            if(i != j && i != (j ^ 1) && Edge[i].second == Edge[j].first)
                MAP.A[i][j] = 1;
    }
    GET_E();
    MAP.n = MAP.m = N;
    Map.n = 1; Map.m = N;
    for(int i = 0; i < In; i++) Map.A[0][EI[i]] = 1;
    MAP = pow_mod(MAP, K-1);
    ANS = mul(Map, MAP);
    int cnt = 0;
    for(int i = 0; i < Out; i++)
    {
        cnt += ANS.A[0][EO[i]];
        cnt %= p;
    }
    printf("%d", cnt);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值