「Codeforces 632F」Magic Matrix

本文介绍了一种用于判定魔法矩阵的高效算法。魔法矩阵需满足特定的对称性和边权条件,通过构造无向完全图并利用MST和DFS,可以在O(n^2)的时间复杂度内完成判定。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

称一个矩阵为魔法矩阵,当且仅当满足一下三点:

  1. ∀1≤i,j≤n,ai,j=aj,i\forall 1 \le i,j \le n, a_{i,j}=a_{j,i}∀1i,jn,ai,j=aj,i
  2. ∀1≤i≤n,ai,i=0\forall 1 \le i \le n, a_{i,i} = 0∀1in,ai,i=0
  3. ∀1≤i,j,k≤n,ai,j≤max⁡(ai,k,ak,j)\forall 1 \le i,j,k\le n, a_{i,j} \le \max(a_{i,k}, a_{k,j})∀1i,j,kn,ai,jmax(ai,k,ak,j)
    询问一个矩阵是否为魔法矩阵
    n≤2500n \le 2500n2500

将矩阵抽象成一个有 nnn 个点 n2n^2n2 条边的无向完全图,边权为 ai,ja_{i,j}ai,j
fi,jf_{i,j}fi,j 表示从 iii 出发到 jjj 的所有路径上最长的边的最小值,显然 ai,j≥fi,ja_{i,j} \ge f_{i,j}ai,jfi,j
根据题意,因为 ai,j≤max⁡(ai,k,ak,j)a_{i,j} \le \max(a_{i,k}, a_{k,j})ai,jmax(ai,k,ak,j),而 ai,k≤max⁡(ai,l,al,k)a_{i,k} \le \max(a_{i,l},a_{l,k})ai,kmax(ai,l,al,k),所以 ai,j≤max⁡(ai,k1,ak1,k2...akm,j)a_{i,j} \le \max(a_{i,k_1}, a_{k_1,k_2}...a_{k_m, j})ai,jmax(ai,k1,ak1,k2...akm,j),即 ai,j≤fi,ja_{i,j} \le f_{i,j}ai,jfi,j
所以 ai,j=fi,ja_{i,j} = f_{i,j}ai,j=fi,j,这样就只要用 MST\mathrm{MST}MSTDFS\mathrm{DFS}DFS 就可以在 O(n2)O(n^2)O(n2) 判断条件了。

#include <cstdio>
#include <cstring>
#define Min(_A, _B) (_A < _B ? _A : _B)
#define Max(_A, _B) (_A > _B ? _A : _B)
#define R register
int n, a[2510][2510];
bool vis[2510]; int dis[2510], from[2510], Point[2510], Next[5010], To[5010], W[5010], q;
void Add(R int u, R int v, R int w)
{
	Next[++q] = Point[u]; Point[u] = q; To[q] = v; W[q] = w;
	Next[++q] = Point[v]; Point[v] = q; To[q] = u; W[q] = w;
}
bool DFS(R int u, R int from, R int pos, R int val)
{
	if(a[pos][u] != val) return 1; 
	for(R int j = Point[u]; j; j = Next[j]) if(To[j] != from && DFS(To[j], u, pos, Max(W[j], val))) return 1;
	return 0;
}
int main()
{
	scanf("%d", &n);
	for(R int i = 1; i <= n; ++i)
		for(R int j = 1; j <= n; ++j)
			scanf("%d", &a[i][j]);
	for(R int i = 1; i <= n; ++i)
		for(R int j = 1; j <= n; ++j)
			if(a[i][j] != a[j][i])
			{
				puts("NOT MAGIC");
				return 0;
			}
	memset(dis, 127, sizeof(dis)); dis[1] = 0;
	for(R int i = 1; i <= n; ++i)
	{
		R int pos = 0;
		for(R int j = 1; j <= n; ++j) if(!vis[j] && dis[pos] > dis[j]) pos = j;
		if(i > 1) Add(pos, from[pos], dis[pos]);
		vis[pos] = 1;
		for(R int j = 1; j <= n; ++j) if(!vis[j] && a[pos][j] < dis[j])
		{ from[j] = pos; dis[j] = a[pos][j]; }
	}
	for(R int i = 1; i <= n; ++i) if(DFS(i, i, i, 0)){ puts("NOT MAGIC"); return 0; }
	puts("MAGIC");
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值