CF632F

题目大意:

给你一个 n阶方阵 An,判断它是否满足:

  1. aii=0
  2. aij=aji;
  3. aijmax{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;
}

  

猜你喜欢

转载自www.cnblogs.com/ckr1225/p/9118540.html