邻接矩阵

邻接矩阵


CF402E Strictly Positive Matrix

对角线之和>0 , 每个元素>=0

问是否存在(a^k) 满足每个元素>0

题解

学过矩阵的人都知道对于本题来说整个矩阵里的元素只需要分为两种,一种是为0,一种是不为0。

这样我们就得到了一个01矩阵

转换:

邻接矩阵表示该矩阵对应的有向图,第(i)行第(j)列表示第(i)个点能否直接走到第(j)个点,而这个矩阵的(k)次幂中,第(i)行第(j)列表示第(i)个点走恰好(k)步能否走到第(j)个点。

于是我们就把这道题转到图论上去了

由邻接矩阵幂的性质我们猜想当且仅当这个矩阵代表的有向图为强连通图的时候答案为YES。

证明:

当这个矩阵(01矩阵,边权为1)代表的有向图为强连通图的时候,设有自环的那个点为mid,取(U,V)两点使得U–>mid–>V最短路径的长度最大,记为k。

那么我们考虑任意一对((u,v)),我们构造一条(u–>mid–>v)的最短路径,如果这条路径的长度(<k),那么我们走mid的自环直到长度补齐为止,而(>k)显然是不可能的,这个时候我们就找到了这样的正整数(k),使得该矩阵的(k)次幂中每一项全部为正数,此时答案为YES。

(利用上面一段证明我们可以如果k存在那么其上界为2n,因此50分做法只需要取一个矩阵的2n次幂判断即可。)

当这个矩阵代表的不是强连通图,取((u,v))使(u)始终不能到达(v),无论取几次幂,该矩阵中第(u)行第(v)列始终为0,此时答案为NO。

直接BFS的时间复杂度为(O(n^3)) ,而用Tarjan算法的话时间复杂度为(O(n^2))

可乐

在原先 (n) 个点的基础上加一个点 (0),表示机器人自爆后的去处,每个点都向 (0) 连一条单向边

对于每个点可以添加一个自环,走这个自环就代表停在这里

只需要建出邻接矩阵,然后矩阵快速幂求出点 (1) 到每一点的方案数,求和即可

注意答案矩阵一开始要build

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;
const int P=2017;
inline int read() {
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
	return f*x;
}
int n,m;
struct matrix{
	int a[40][40];
	matrix(){ memset(a,0,sizeof(a)); }
	void build() {
		for(int i=0;i<=n;i++)
			a[i][i]=1;
	}
}G,ans;
matrix operator * (const matrix &x,const matrix &y) {
	matrix z;
	for(int k=0;k<=n;k++)
		for(int i=0;i<=n;i++)
			for(int j=0;j<=n;j++)
				z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j]%P)%P;
	return z;
}
int main() {
	n=read();m=read();
	int x,y;
	for(int i=1;i<=m;i++) {
		x=read();y=read();
		G.a[x][y]=G.a[y][x]=1;
	}
	int k=read();
	for(int i=1;i<=n;i++) {
		G.a[i][0]=1;
		G.a[i][i]=1;
	}
	G.a[0][0]=1;
	ans.build();
	do{
		if(k&1) ans=ans*G;
		G=G*G;
		k>>=1;
	}while(k);
	int Ans=0;
	for(int i=0;i<=n;i++)
		(Ans+=ans.a[1][i])%=P;
	cout<<Ans;
	return 0;
}


原文地址:https://www.cnblogs.com/ke-xin/p/13572272.html