图论-平方图
问题
此文我们讨论一下对一个邻接矩阵进行平方,三次方,n次方的意义和相应的邻接链表的算法。
首先我们定义 k × k k \times k k×k邻接矩阵 G G G,则元素
G x y 2 = ∑ i = 1 k G x k ⋅ G k y G^{2}_{xy}= \sum_{i=1}^{k}G_{xk} \cdot G_{ky} Gxy2=i=1∑kGxk⋅Gky
因此邻接矩阵平方相乘的意义是得到平方图,即有向图 G = ( V , E ) G=(V,E) G=(V,E)的平方图是图 G 2 = ( V , E 2 ) G^{2}=(V,E^{2}) G2=(V,E2),边 ( u , v ) ∈ E 2 (u,v) \in E^{2} (u,v)∈E2的充分必要条件的图 G G G包含一条路径最多由两条边构成从 u u u到 v v v的路径。如果不包含自环(对角线元素为1)那就去掉“最多”。
同理,三次方相乘就是存在一条路径(最多)三条边可达;n次方就是存在一条路径(最多)n条边可达。
这就是矩阵相乘和图论之间的关系。
相应的,邻接链表也可以写出该算法。遍历每一个u点的邻接链表得到k点,其中存在边 ( u , k ) (u,k) (u,k),然后再遍历k的邻接链表得到节点v,则存在边 ( k , v ) (k,v) (k,v),则在图 G 2 G^{2} G2中一定存在边 ( u , v ) (u,v) (u,v)。
例题
平方图+矩阵快速幂
#include <bits/stdc++.h>
using namespace std;
struct Matrix
{
int arr[35][35];
int size;
Matrix(int s):size(s)
{
for(int i = 0; i<size; i++)
for(int j=0; j<size; j++)
arr[i][j] = 0;
}
void one()
{
for(int i = 0; i<size; i++)
arr[i][i] = 1;
}
Matrix operator*(const Matrix& m)
{
Matrix res(size);
for(int i = 0; i<size; i++)
for(int j = 0; j<size; j++)
for(int k =0; k<size; k++)
res.arr[i][j]+= arr[i][k] * m.arr[k][j];
return res;
}
};
int main()
{
int n,m;
cin >> n >> m;
Matrix A(n);
for(int i = 0; i<n; i++)
{
A.arr[i][(i+1) %n] = A.arr[i][(i-1+n) %n] = 1;
}
Matrix ans(n);
ans.one();
for(; m != 0; m >>= 1)
{
if((m&1) == 1) ans = ans * A;
A = A * A;
}
cout << ans.arr[0][0];
return 0;
}