题意
给定一个 n∗n 的矩阵 A,每个元素都非负判断是否存在一个整数 k 使得 A^k 的所有元素 >0 n≤2000(矩阵中[i][i]保证为1)
题解
考虑矩阵$A*A$的意义 ,设得到的矩阵为B矩阵中的一个元素$B[i][j]=sum_{k=1}^{n}A[i][k]*A[k][j]$,$A[i][k]*A[k][j]$非负当且仅当$A[i][k]$和$A[k][j]$非负。
这跟$弗洛伊德$差不多,枚举中间点,我们把$A[i][j]$非负理解为一个图中有一条$A$从$i$到$j$的边,$A^k$中$A[i][j]$就代表从i到j有没有一条长度小于等于$k$的路径。
此题本质上就是问根据所给矩阵建图,是否全图为一个强联通分量。
所以就上$Tarjan$模板就行了
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; const int N=3000; int cnt,head[N]; int dfn[N],low[N],stack[N],top,tot,vis[N],num,c[N]; int n; struct edge{ int to,nxt; }e[5000000]; void add(int u,int v){ cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } void Tarjan(int u){ dfn[u]=low[u]=++tot; stack[++top]=u; vis[u]=1; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if(dfn[v]==0){ Tarjan(v); low[u]=min(low[u],low[v]); } else if(vis[v])low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]){ int x; num++; do{ x=stack[top--]; c[x]=num; vis[x]=0; }while(u!=x); } } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++) for(int j=1,a;j<=n;j++){ scanf("%d",&a); if(i==j||a==0)continue; add(i,j); } for(int i=1;i<=n;i++){ if(dfn[i]==0)Tarjan(i); } for(int i=1;i<=n;i++){ if(c[i]>1){ printf("NO"); return 0; } } printf("YES"); return 0; }