题目大意
还算是比较清楚,贴个题面吧。
题目分析
一道好题。
一眼看上去,就是个 LCA,而本蒟蒻不太会 LCA,只好用了 prim 算法。
首先读入,边读入边判断是否满足要求。如果 i , j i, j i,j 不相同且 a i , j a_{i,j} ai,j 是 0 0 0,说明无效,直接输出 NO,当然,如果 i , j i, j i,j 相同且 a i , j a_{i,j} ai,j 不是 0 0 0,说明也无效,直接输出 NO,后面用 prim 进行处理即可。
代码中的 e i e_i ei 存邻接表, d i s i dis_i disi 存从起点到 i i i 的距离, v i s i vis_i visi 存是否经过了点 i i i, a i a_i ai 是邻接表。
当然不能直接套模板,而需要在模板上进行一些修改,具体见代码吧。
代码比较长,请不要介意:
#include <bits/stdc++.h>
using namespace std;
struct edge
{
int nxt, to, value;
}e[8005];
int h[4005], dis[4005], last[4005];
bool vis[4005];
int a[4005][4005];
int n, m, cnt = 0, ans = 0;
inline void add(int a, int b, int c)
{
e[++cnt].to = b;
e[cnt].value = c;
e[cnt].nxt = h[a];
h[a] = cnt;
}
inline void prim()
{
for(int i = 0; i <= n; i++) dis[i] = 2147483647;
dis[1] = 0;
int tot = 0;
while(1)
{
int u = 0;
for(int i = 1; i <= n; i++)
if(!vis[i] && dis[i] < dis[u])
u = i;
if(u == 0) break;
vis[u] = 1;
if(u != 1)
{
add(u, last[u], dis[u]);
add(last[u], u, dis[u]);
}
for(int i = 1; i <= n; i++)
{
if(vis[i]) continue;
if(dis[i] > a[u][i])
{
dis[i] = a[u][i];
last[i] = u;
}
}
}
}
inline void dfs(int u, int f)
{
for(int i = h[u]; i; i = e[i].nxt)
{
int v = e[i].to;
if(v == f) continue;
dis[v] = dis[u] + e[i].value;
dfs(v, u);
}
}
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-') f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
int main()
{
n = read();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
{
a[i][j] = read();
if(i != j && a[i][j] == 0)
{
printf("NO");
return 0;
}
if(i == j && a[i][j] != 0)
{
printf("NO");
return 0;
}
}
prim();
for(int i = 1; i <= n; i++)
{
dis[i] = 0;
dfs(i, 0);
for(int j = 1; j <= n; j++)
if(dis[j] != a[i][j])
{
printf("NO");
return 0;
}
}
printf("YES");
return 0;
}