orz 峰
由于不是正数就是 (0),可以把正数看成 (1),变成了 (01) 矩阵。
邻接矩阵的 (k) 次幂中,({A^k}_{i,j}) 代表 (i) 到 (j) 是否有长度为 (k) 的路径。
这个题变成了是否存在一个 (k),使得任意两点之间都有长度为 (k) 的路径,初始给的 (A) 即为告诉你哪些点直接直接有边相连。
数据保证了 (sum_{i=1}^n a_{i,i}>0),也就是至少存在一个子环。
那么问题可以转化为给你一张点数为 (n) 的有向图,询问是否两两强连通。因为一定存在一个自环,则可以把 (k) 看作一个很大的数,如果让一个点走到另一个点的时候先走到那个自环的位置把多余的路程消耗完了,再走到目的地的点,即可看为任意两点都有长度为 (k) 的路径。
点数 (leq 2000),边数 (leq 2000^2),直接 dfs 是 (mathcal{O}(n^3)) 的。考虑实际上是问整张图是否是一个 SCC,直接 Tarjan 缩点即可。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<stack>
#include<cstring>
typedef long long ll;
ll mod;
template <typename T> T Add(T x, T y) { return (x + y >= mod) ? (x + y - mod) : (x + y); }
template <typename T> T cAdd(T x, T y) { return x = (x + y >= mod) ? (x + y - mod) : (x + y); }
template <typename T> T Mul(T x, T y) { return x * y % mod; }
template <typename T> T Mod(T x) { return x < 0 ? (x + mod) : x; }
template <typename T> T Max(T x, T y) { return x > y ? x : y; }
template <typename T> T Min(T x, T y) { return x < y ? x : y; }
template <typename T> T Abs(T x) { return x < 0 ? -x : x; }
template <typename T> T chkmax(T &x, T y) { return x = x > y ? x : y; }
template <typename T>
T &read(T &r) {
r = 0; bool w = 0; char ch = getchar();
while(ch < '0' || ch > '9') w = ch == '-' ? 1 : 0, ch = getchar();
while(ch >= '0' && ch <= '9') r = (r << 3) + (r <<1) + (ch ^ 48), ch = getchar();
return r = w ? -r : r;
}
inline int lowbit(int x) { return x & (-x); }
int popcount(int x) { int sumq = 0; while(x) x -= lowbit(x), ++sumq; return sumq; }
ll qpow(ll x, ll y) {
ll sumq = 1;
while(y) {
if(y & 1) sumq = sumq * x % mod;
x = x * x % mod;
y >>= 1;
}
return sumq;
}
const int N = 2010;
std::queue<int>q;
std::stack<int>st;
int n, m, a[N][N];
int dfn[N], low[N], icnt;
int va[N], val[N], blo[N], bnt, f[N];
bool vis[N];
//Edge----------------------------
int head[N], ent;
struct Edge {
int next, to;
}e[N*N];
inline void add(int x, int y) {
e[++ent].to = y; e[ent].next = head[x]; head[x] = ent;
}
//dfs-----------------------------
void dfs(int x) {
dfn[x] = low[x] = ++icnt; st.push(x);
for(int i = head[x]; i; i = e[i].next) {
int v = e[i].to;
if(blo[v]) continue;
if(!dfn[v]) {
dfs(v);
low[x] = Min(low[x], low[v]);
}
else low[x] = Min(low[x], dfn[v]);
}
if(low[x] == dfn[x]) {
++bnt;
do {
int top = st.top(); st.pop();
val[bnt] += va[top];
blo[top] = bnt;
if(top == x) break;
} while(true);
}
}
void dfs2(int x) {
if(vis[x]) return ;
vis[x] = 1;
for(int i = head[x]; i; i = e[i].next)
dfs2(e[i].to);
}
signed main() { //freopen("in.txt", "r", stdin);
read(n);
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= n; ++j) {
read(a[i][j]);
if(a[i][j] && i != j) add(i, j);
}
for(int i = 1; i <= n; ++i)
if(!dfn[i])
dfs(i);
if(bnt == 1) puts("YES");
else puts("NO");
return 0;
}