邻接矩阵的运算

邻接矩阵运算的应用

矩阵的乘法、快速幂

struct Matrix {
    int s[51][51];
    Matrix() { memset(s,0,sizeof(s)); }
    int *operator [](int x) { return s[x]; }
}M;
Matrix operator *(Matrix a,Matrix b) { // 矩阵乘法
    Matrix c;
    for(int k=1; k<=n; ++k)
        for(int i=1; i<=n; ++i)
            if(a[i][k])
                for(int j=1; j<=n; ++j)
                    if(b[k][j])
                        (c[i][j]+=a[i][k]*b[k][j])%=mo;
    return c;
}
Matrix operator ^(Matrix a,int b) { // 矩阵快速幂
    Matrix ans;
    for(int i=1; i<=n; ++i) ans[i][i]=1;
    for(;b;b>>=1,a=a*a) if(b&1) ans=ans*a;
    return ans;
}

1.[USACO07NOV]牛继电器Cow Relays

https://www.luogu.org/problemnew/show/P2886

题目大意:给出一张无向连通图,求S到E经过k条边的最短路

如果我们有两个矩阵
其中一个矩阵代表恰好经过x条边的最短路
另一个矩阵代表恰好经过y条边的最短路
那么将这两个矩阵相结合就代表恰好经过x+y条边的最短路
$ c[i][j]=min(c[i][j],a[i][k]+b[k][j]); $

这道题是一个模型:邻接矩阵求经过k条边的最短路(简称k边最短路)

2.[ZJOI2005]沼泽鳄鱼

https://www.luogu.org/problemnew/show/P2579

首先不看食人鱼的情况
我们要求从s到t可以经过k条边(可以经过重复点)的方案数
这个是邻接矩阵运算最擅长的
与k边最短路不同的是
方案数是根据乘法原理得来的
所以我们在求解的时候要用到矩阵乘法

那么再把食人鱼放入到池塘里
发现食人鱼的周期奇短无比,都是12的因子
很小,所以我们可以构造出12个邻接矩阵。
利用这12个邻接矩阵
便既可以完全的表示出食人鱼的行动周期
也可以统计人活动的情况周期
就让食人鱼在某一时间点所在的地点情况数清零即可
然后以12为周期进行矩阵乘法

非常好的一道邻接矩阵的题目。

模型:求一个点到另一个点经过k条边的方案数(简称st-k方案数)

3.[TJOI2017]可乐

https://www.luogu.org/problemnew/show/P3758
这道题的构造巧妙无比
先不看有爆炸,可以停留的情况,这道题就变成了st-k方案数,只不过这里是从1出发,到1在内的所有节点的方案数

再来看可以停留这个条件。不就是从一个点走到自己吗?所以,再邻接矩阵中,我们只需要让一个点从自己连到自己就可以了。

爆炸怎么办?我们可以新开一个节点n+1,所有点向n+1连一条边,而它不向除自己以外的任何点连边。为什么n+1要向自己连边呢?这就像在一个点停留一样。如果不向自己连边,那么在下一个矩阵中它将不复存在。

总结

这三道题都是十分经典的邻接矩阵运算题目
都有着非常好的价值和意义
可以说
如果完全掌握了这三道题
那么邻接矩阵的运算可以说是轻车熟驾了。

code

T1

// luogu-judger-enable-o2
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#define rg register int
#define ll long long
#define RG register
#define il inline
using namespace std;

il int gi() {
    rg x=0,o=0;RG char ch=getchar();
    while(ch!='-'&&(ch<'0'||'9'<ch)) ch=getchar();
    if(ch=='-') o=1,ch=getchar();
    while('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return o?-x:x;
}

#define SZ 2000001
int cnt,mp[SZ];
#define INF 2147483647
#define Getmin(a,b) (a)=(a)<(b)?(a):(b)
struct Matrix{ll a[201][201];};
Matrix dis,ans;
Matrix mul(Matrix a,Matrix b) {
    Matrix c;
    for(rg i=1; i<=cnt; ++i)
        for(rg j=1; j<=cnt; ++j)
            c.a[i][j]=INF;
    for(rg k=1; k<=cnt; ++k)
        for(rg i=1; i<=cnt; ++i)
            for(rg j=1; j<=cnt; ++j)
                Getmin(c.a[i][j],a.a[i][k]+b.a[k][j]);
    return c;
}
int n,m,s,t;

il void power(rg b) {
    for(rg i=1; i<=cnt; ++i) ans.a[i][i]=0;
    while(b) {
        if(b&1) ans=mul(ans,dis);
        dis=mul(dis,dis);
        b>>=1;
    }
}
int main() {
    n=gi(),m=gi(),s=gi(),t=gi();
    memset(mp,-1,sizeof(mp));
    memset(ans.a,0x3f,sizeof(ans.a));
    memset(dis.a,0x3f,sizeof(dis.a));
    for(rg u,v,w,i=1; i<=m; ++i) 
    {
        w=gi(),u=gi(),v=gi();
        if(mp[u]==-1) mp[u]=++cnt;
        if(mp[v]==-1) mp[v]=++cnt;
        u=mp[u],v=mp[v];
        Getmin(dis.a[u][v],w);
        dis.a[v][u]=dis.a[u][v];
    }
    power(n);
    printf("%lld",ans.a[mp[s]][mp[t]]); 
    return 0;
}

T2

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#define rg register int
#define ll long long
#define RG register
#define il inline
using namespace std;

il int gi()  {
    rg x=0,o=0;RG char ch=getchar();
    while(ch!='-'&&(ch<'0'||'9'<ch)) ch=getchar();
    if(ch=='-') o=1,ch=getchar();
    while('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return o?-x:x;
}

int N,M,S,T,K,FN;

struct Matrix {
    int s[51][51];
    Matrix() {memset(s,0,sizeof(s));}
    int *operator [](int x) {return s[x];}
}dis[13];

#define MOD 10000
Matrix operator *(Matrix a,Matrix b) {
    Matrix c;
    for(rg k=1; k<=N; ++k)
        for(rg i=1; i<=N; ++i)
            if(a[i][k])
                for(rg j=1; j<=N; ++j)
                    if(b[k][j])
                        (c[i][j]+=a[i][k]*b[k][j])%=MOD;
    return c;
}
Matrix operator ^(Matrix a,int b) {
    Matrix ans;
    for(rg i=1; i<=N; ++i) ans[i][i]=1;
    for(;b;b>>=1,a=a*a) if(b&1) ans=ans*a;
    return ans;
}

int p[5];
int main() {
    N=gi(),M=gi(),S=gi()+1,T=gi()+1,K=gi();
    // 因为题目给出的是从 0 开始,所以我们要+1 来强制 从1开始
    for(rg x,y,i=1; i<=M; ++i) {
        x=gi()+1,y=gi()+1;
        for(rg j=1; j<=12; ++j)
            dis[j][x][y]=dis[j][y][x]=1;
    }
    FN=gi();
    for(rg i=1; i<=FN; ++i) {
        p[0]=gi();
        for(rg j=1; j<=p[0]; ++j) p[j]=gi();
        for(rg j=1; j<=12; ++j)
            for(rg pos=j%p[0]+1,k=1; k<=N; ++k)
                dis[j][k][p[pos]+1]=0;
    }
    for(rg i=1; i<=N; ++i) dis[0][i][i]=1;
    for(rg i=1; i<=12; ++i) dis[0]=dis[0]*dis[i];
    Matrix Ans=dis[0]^(K/12);
    for(rg i=1; i<=K%12; ++i) Ans=Ans*dis[i];
    printf("%d",Ans.s[S][T]);
    return 0;
}

T3

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>

#define Getmax(a,b) (a)=(a)>(b)?(a):(b)
#define Getmin(a,b) (a)=(a)<(b)?(a):(b)
#define lb lower_bound
#define ub upper_bound
#define pb push_back
#define ll long long
#define gc getchar

using namespace std;

int gi() {
  int x=0,o=0;char ch=getchar();
  while(ch!='-'&&(ch<'0'||'9'<ch)) ch=getchar();
  if(ch=='-') o=1,ch=getchar();
  while('0'<=ch&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
  return o?-x:x;
}

const int mo=2017;
int n,m;

struct Matrix {
    int s[51][51];
    Matrix() { memset(s,0,sizeof(s)); }
    int *operator [](int x) { return s[x]; }
}M;
Matrix operator *(Matrix a,Matrix b) {
    Matrix c;
    for(int k=1; k<=n; ++k)
        for(int i=1; i<=n; ++i)
            if(a[i][k])
                for(int j=1; j<=n; ++j)
                    if(b[k][j])
                        (c[i][j]+=a[i][k]*b[k][j])%=mo;
    return c;
}
Matrix operator ^(Matrix a,int b) {
    Matrix ans;
    for(int i=1; i<=n; ++i) ans[i][i]=1;
    for(;b;b>>=1,a=a*a) if(b&1) ans=ans*a;
    return ans;
}

int main() {
    n=gi()+1,m=gi();
    for(int i=1; i<=m; ++i) {
        int u=gi(),v=gi();
        M[u][v]=M[v][u]=1;
    }
    for(int i=1; i<=n; ++i) M[i][i]=1;
    for(int i=1; i<=n-1; ++i) M[i][n]=1;
    int t=gi(),ans=0;
    M=M^t;
    for(int i=1; i<=n; ++i) (ans+=M[1][i])%=mo;
    printf("%d",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/tply/p/9162263.html