http://codeforces.com/problemset/problem/402/E
You have matrix a of size n × n. Let's number the rows of the matrix from 1 to n from top to bottom, let's number the columns from 1 to nfrom left to right. Let's use aij to represent the element on the intersection of the i-th row and the j-th column.
Matrix a meets the following two conditions:
- for any numbers i, j (1 ≤ i, j ≤ n) the following inequality holds: aij ≥ 0;
- .
Matrix b is strictly positive, if for any numbers i, j (1 ≤ i, j ≤ n) the inequality bij > 0 holds. You task is to determine if there is such integer k ≥ 1, that matrix ak is strictly positive.
Input
The first line contains integer n (2 ≤ n ≤ 2000) — the number of rows and columns in matrix a.
The next n lines contain the description of the rows of matrix a. The i-th line contains n non-negative integers ai1, ai2, ..., ain(0 ≤ aij ≤ 50). It is guaranteed that .
Output
If there is a positive integer k ≥ 1, such that matrix ak is strictly positive, print "YES" (without the quotes). Otherwise, print "NO" (without the quotes).
题意:給定一个矩阵a,满足a(i,j)>=0且a(i,i)>0。问是否存在k,使得a^k的每一个元素都大于0。
思路:把给定矩阵当作一个邻接矩阵,a(i,j)表示有向边i->j的边权。
如果a是0/1矩阵,那么a^k的任一元素a(i,j)表示从i到j恰好经过k条边可达的方案数。
如果想要详细了解,2008国家集训队论文:俞华程《矩阵乘法在信息学中的应用》,这篇太好了,信息量太大,我有时间再看。
对于这道题,a(i,i)>0说明i->i有自环,题目等价于是否图中任意两点均可达。
用floyd当然方便,但是复杂度承受不了。
只需要知道图中任意两点是否可达,即整个图是不是强连通图,用线性的tarjan即可。
为什么floyd的复杂度高出那么多呢?floyd可以找出任意两点的最短路,过大的信息量对于本题太多冗余,本题只需要知道是否任意两点可达,即是不是强连通图。
#include<bits/stdc++.h>
using namespace std;
#define maxn 3000
int n;
vector<int> G[maxn];
int pre[maxn],lowlink[maxn],sccno[maxn],dfs_clock,scc_cnt;
stack<int> s;
void dfs(int u)
{
pre[u]=lowlink[u]=++dfs_clock;
s.push(u);
for(int i=0;i<G[u].size();i++)
{
int v=G[u][i];
if(!pre[v])
{
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
}
else if(!sccno[v])
{
lowlink[u]=min(lowlink[u],pre[v]);
}
}
if(lowlink[u]==pre[u])
{
scc_cnt++;
if(scc_cnt==2){puts("NO");exit(0);}
for(;;)
{
int x=s.top();s.pop();
sccno[x]=scc_cnt;
if(x==u)break;
}
}
}
void find_scc()
{
for(int i=1;i<=n;i++)if(!pre[i])dfs(i);
}
int main()
{
//freopen("input.in","r",stdin);
int x;
cin>>n;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
{
scanf("%d",&x);
if(x)G[i].push_back(j);
}
find_scc();
for(int i=1;i<=n;i++)if(sccno[i]!=sccno[1]){puts("NO");exit(0);}
puts("YES");exit(0);
}