题目大意:
给你一个 n阶方阵 An,判断它是否满足:
- aii=0;
- aij=aji;
- aij≤max{aik,ajk}。
其中n<=2500
题解:两个特判题目中给的比较清楚很简单的可以判定掉
考虑如何构造ai,j<=max(ai,k,ajk)
显然的我们索性让i,j之间连一条ai,j的边
然后跑一遍最大生成树
求出两点之间的最大值,看看是否与给定的ai,j矛盾即可
#include<bits/stdc++.h>
#define N 5005
using namespace std;
int fa[N],G[N][N],a[N][N],head[N],n,kk,cnt;
struct Node{int x,y,d;}p[N*N];
struct Tree{int nxt,to,step;}e[N];
inline bool cmp(Node aa,Node bb){return aa.d<bb.d;}
inline void link(int x,int y,int z){e[++kk].nxt=head[x];e[kk].to=y;e[kk].step=z;head[x]=kk;}
inline int find(int x){if(fa[x]==x)return x;return fa[x]=find(fa[x]);}
inline void make(int x,int y){fa[find(x)]=find(y);}
void dfs(int u,int fa,int p,int mx){
for (int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if (v==fa) continue;
G[p][v]=max(mx,e[i].step);
dfs(v,u,p,G[p][v]);
}
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) scanf("%d",&a[i][j]);
for (int i=1;i<=n;i++) if (a[i][i]) return puts("NOT MAGIC"),0;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) if (a[i][j]!=a[j][i]) return puts("NOT MAGIC"),0;
for (int i=1;i<=n;i++)
for (int j=i+1;j<=n;j++) p[++cnt].x=i,p[cnt].y=j,p[cnt].d=a[i][j];
sort(p+1,p+cnt+1,cmp);
for (int i=1;i<=n;i++) fa[i]=i;
for (int i=1;i<=cnt;i++){
if (find(p[i].x)!=find(p[i].y)){
link(p[i].x,p[i].y,p[i].d);
link(p[i].y,p[i].x,p[i].d);
make(p[i].x,p[i].y);
}
else continue;
}
for (int i=1;i<=n;i++) dfs(i,-1,i,0);
for (int i=1;i<=n;i++)
for (int j=i+1;j<=n;j++) if (G[i][j]!=a[i][j]) return puts("NOT MAGIC"),0;
puts("MAGIC");
return 0;
}