codeforces 632F. Magic Matrix (最小生成树)
You're given a matrix A of size n × n.
Let's call the matrix with nonnegative elements magic if it is symmetric (so aij = aji), aii = 0 and aij ≤ max(aik, ajk) for
all triples i, j, k. Note that i, j, k do
not need to be distinct.
Determine if the matrix is magic.
As the input/output can reach very huge size it is recommended to use fast input/output methods: for example, prefer to usescanf/printf instead of cin/cout in
C++, prefer to use BufferedReader/PrintWriter instead ofScanner/System.out in Java.
The first line contains integer n (1 ≤ n ≤ 2500)
— the size of the matrix A.
Each of the next n lines contains n integers aij (0 ≤ aij < 109)
— the elements of the matrix A.
Note that the given matrix not necessarily is symmetric and can be arbitrary.
Print ''MAGIC" (without quotes) if the given matrix A is
magic. Otherwise print ''NOT MAGIC".
3
0 1 2
1 0 2
2 2 0
MAGIC
2
0 1
2 3
NOT MAGIC
4
0 1 2 3
1 0 3 4
2 3 0 5
3 4 5 0
NOT MAGIC
题意:给你一个n*n的矩阵,让你判断这个矩阵是不是魔力矩阵,魔力矩阵的定义为:1.对角线都为0. 2.左下角的数和右上角的数对称相等. 3.对于任意一个格子(i,j)要满足对于任意的k,a[i][j]<=max(a[i][k],a[k][j]),k为1~n中的任意数,可以与i,j相等。
思路:有两种思路,第一种一种比较容易想,因为要满足对于任意的k,a[i][j]<=max(a[i][k],a[k][j]),k为任意数,那么a[i][j]就满足a[i][j]<=max(a[i][k],a[j][k]),因为满足前两种条件的前提下a[k][j]=a[j][k].那么再把不等式转换,即变成a[i][j]要小于等于n对i,j行上下对应的两个数的最大值的最小值,因为k是任意取的.那么我们可以先把所有的点的x坐标,y坐标,大小放入结构体中,然后根据大小从小到大排序.然后开一个bitset<maxn>bt[maxn],b[x]表示的是x行中比a[i][j]小的列数的表示(如果x行当前的列数小于a[i][j],该位就置为1),那么对于现在这个数,所有小于这个数的都在i,j行的bitset里,如果这两行的bitset交非空,说明存在某个k,使a[i][j]>a[i][k]且a[i][j]>a[j][k],这样就是不符合条件的.
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<bitset>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef long double ldb;
#define inf 99999999
#define pi acos(-1.0)
#define maxn 2505
int a[maxn][maxn];
struct node{
int len,l,r;
}e[maxn*maxn/2];
bool cmp(node a,node b){
return a.len<b.len;
}
bitset<maxn>bt[maxn];
int main()
{
int n,m,i,j,flag;
while(scanf("%d",&n)!=EOF)
{
flag=1;
int tot=0;
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
scanf("%d",&a[i][j]);
if(i<j){
tot++;
e[tot].len=a[i][j];
e[tot].l=i;e[tot].r=j;
}
}
}
for(i=1;i<=n;i++){
if(a[i][i]!=0){
flag=0;break;
}
}
if(flag==0){
printf("NOT MAGIC\n");continue;
}
for(i=1;i<=n;i++){
for(j=i+1;j<=n;j++){
if(a[i][j]!=a[j][i]){
flag=0;break;
}
}
if(!flag)break;
}
if(flag==0){
printf("NOT MAGIC\n");continue;
}
sort(e+1,e+1+tot,cmp);
int t=1;
for(i=1;i<=tot;i++){
while(t<=tot && e[t].len<e[i].len ){
bt[e[t].l ][e[t].r ]=1;
bt[e[t].r ][e[t].l ]=1;
t++;
}
if((bt[e[i].l ]&bt[e[i].r ] ).any() ){
flag=0;break;
}
}
if(flag==0)printf("NOT MAGIC\n");
else printf("MAGIC\n");
}
return 0;
}
第二种思路:是把这个矩阵看做一张图,a[i][j]表示i和j点之间连一条a[i][j]的边,我们设b[i][j]为i节点到j节点之间所有路径最长边的最小值,那么根据定义可得a[i][j]>=b[i][j].然后如果是魔力矩阵,那么要满足a[i][j]<=max(a[i][k]+a[k][j]),因为a[i][k]<=max(a[i][k1]+a[k1][k])...可以多次递归下去,所以a[i][j]<=max(a[i][k1],a[k1][k2]+...+a[km][j),即相当于a[i][j]<=b[i][j],所以a[i][j]=b[i][j].接下来我们就要先的到b[i][j],这里我们可以用最小生成树做,因为最小生成树每次都是加最短的边,所以能够保证使得最大的边最小.把最小生成树求出来之后,我们枚举1~n的每一个点为根节点,dfs一遍所有点,记录根到其他所有点的最小生成树路径中的最小边就行了.
#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<algorithm>
#define inf 99999999
#define pi acos(-1.0)
#define maxn 2505
#define MOD 1000000007
using namespace std;
typedef long long ll;
typedef long double ldb;
int a[maxn][maxn];
struct node{
int len,l,r;
}e[maxn*maxn/2];
int pre[maxn],ran[maxn],num[maxn],maxx[maxn];
struct edg{
int next,to,len;
}edge[2*maxn];
int first[maxn];
int findset(int x){
int i,j=x,r=x;
while(r!=pre[r])r=pre[r];
while(j!=pre[j]){
i=pre[j];
pre[j]=r;
j=i;
}
return r;
}
bool cmp(node a,node b){
return a.len<b.len;
}
int flag;
void dfs(int u,int father,int x)
{
int i,j,v;
for(i=first[u];i!=-1;i=edge[i].next){
v=edge[i].to;
if(v==father)continue;
maxx[v]=max(maxx[u],edge[i].len);
if(a[x][v]!=maxx[v]){
flag=0;break;
}
dfs(v,u,x);
if(flag==0)break;
}
}
int main()
{
int n,m,i,j;
while(scanf("%d",&n)!=EOF)
{
flag=1;
int tot=0;
for(i=1;i<=n;i++){
pre[i]=i;ran[i]=0;num[i]=1;
for(j=1;j<=n;j++){
scanf("%d",&a[i][j]);
if(i<j){
tot++;
e[tot].len=a[i][j];
e[tot].l=i;e[tot].r=j;
}
}
}
for(i=1;i<=n;i++){
if(a[i][i]!=0){
flag=0;break;
}
}
if(flag==0){
printf("NOT MAGIC\n");continue;
}
for(i=1;i<=n;i++){
for(j=i+1;j<=n;j++){
if(a[i][j]!=a[j][i]){
flag=0;break;
}
}
if(!flag)break;
}
if(flag==0){
printf("NOT MAGIC\n");continue;
}
sort(e+1,e+1+tot,cmp);
int t1,t2,u,v,x,y;
int t=0;
memset(first,-1,sizeof(first));
for(i=1;i<=tot;i++){
u=e[i].l;v=e[i].r;
x=findset(u);
y=findset(v);
if(x==y)continue;
t++;
edge[t].next=first[u];edge[t].to=v;edge[t].len=a[u][v];
first[u]=t;
t++;
edge[t].next=first[v];edge[t].to=u;edge[t].len=a[u][v];
first[v]=t;
if(ran[x]>ran[y]){
pre[y]=x;
num[x]+=num[y];
if(num[x]==n)break;
}
else{
pre[x]=y;
num[y]+=num[x];
if(num[y]==n)break;
if(ran[x]==ran[y])ran[y]++;
}
}
for(j=1;j<=n;j++){
maxx[j]=0;
dfs(j,0,j);
if(flag==0)break;
}
if(flag)printf("MAGIC\n");
else printf("NOT MAGIC\n");
}
return 0;
}
codeforces 632F. Magic Matrix (最小生成树)的更多相关文章
- Codeforces 632F Magic Matrix(bitset)
题目链接 Magic Matrix 考虑第三个条件,如果不符合的话说明$a[i][k] < a[i][j]$ 或 $a[j][k] < a[i][j]$ 于是我们把所有的$(a[i][j ...
- Codeforces 632F - Magic Matrix(暴力 bitset or Prim 求最小生成树+最小瓶颈路)
题面传送门 开始挖老祖宗(ycx)留下来的东西.jpg 本来想水一道紫题作为 AC 的第 500 道紫题的,结果发现点开了道神题. 首先先讲一个我想出来的暴力做法.条件一和条件二直接扫一遍判断掉.先将 ...
- codeforces 632F. Magic Matrix
题目链接 给一个n*n的矩阵, 问是否对角线上的元素全都为0, a[i][j]是否等于a[j][i], a[i][j]是否小于等于max(a[i][k], a[j][k]), k为任意值. 前两个都好 ...
- Educational Codeforces Round 9 F. Magic Matrix 最小生成树
F. Magic Matrix 题目连接: http://www.codeforces.com/contest/632/problem/F Description You're given a mat ...
- CF 1042 E. Vasya and Magic Matrix
E. Vasya and Magic Matrix http://codeforces.com/contest/1042/problem/E 题意: 一个n*m的矩阵,每个位置有一个元素,给定一个起点 ...
- Vasya and Magic Matrix CodeForces - 1042E (概率dp)
大意:给定n*m矩阵, 初始位置(r,c), 每一步随机移动到权值小于当前点的位置, 得分为移动距离的平方, 求得分期望. 直接暴力dp的话复杂度是O(n^4), 把距离平方拆开化简一下, 可以O(n ...
- Codeforces 710C. Magic Odd Square n阶幻方
C. Magic Odd Square time limit per test:1 second memory limit per test:256 megabytes input:standard ...
- Codeforces 1120D Power Tree [最小生成树]
洛谷 Codeforces 这题怎么一个中文题解都没有,是不是你们都认为太水了-- 思路 显然可以用dfs序把每个节点变成给一个区间的叶子节点加上某个数. 显然把叶子序列差分一下变为\(a_1,a_2 ...
- Codeforces 670D1. Magic Powder - 1 暴力
D1. Magic Powder - 1 time limit per test: 1 second memory limit per test: 256 megabytes input: stand ...
随机推荐
- LeetCode-151-中等-翻转字符串里面的单词
问题描述 给定一个字符串,逐个翻转字符串中的每个单词. 说明: 无空格字符构成一个 单词 . 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括. 如果两个单词间有多余的空格,将反转 ...
- 在Linux系统下限制指定目录的大小以及文件/文件夹数量
背景说明 在Linux操作系统下有时需要限制一个指定文件夹的大小和文件夹内可存储的文件数量,有可能是出于安全的考量或者定制化的配置,这里我们提供了一种方案:用dd创建一个空的img镜像,进行格式化的配 ...
- TCP/IP五层模型-传输层-UDP协议
1.定义:UDP:是非面向连接.不可靠的用户数据包协议. 2.应用场景:适合对数据完整性要求不高,但对延迟很敏感,比如即时通信(语音视频聊天等). 3.UDP报文格式: 4.用UDP传输数据的应用层 ...
- C语言指针-从底层原理到花式技巧,用图文和代码帮你讲解透彻
这是道哥的第014篇原创 目录 一.前言 二.变量与指针的本质 1. 内存地址 2. 32位与64位系统 3. 变量 4. 指针变量 5. 操作指针变量 5.1 指针变量自身的值 5.2 获取指针变量 ...
- ip访问本机vs调试项目
环境:win10 vs2019 webapi F5启动调试. 问题:localhost可以访问,127.0.0.1和本机ip访问不了.比如想让别人浏览一下看效果,或者测试人员测试功能,每次修改都有重新 ...
- 【项目实践】手把手带你搞定SSM
以项目驱动学习,以实践检验真知 前言 现在使用Java后端开发使用的技术栈基本上比较统一:Spring + SpringMVC + Mybatis,即大家常说的SSM.虽然现在流行的做法是使用Spri ...
- 【Spring】Spring中的Bean - 3、Bean的作用域
Bean的作用域 简单记录-Java EE企业级应用开发教程(Spring+Spring MVC+MyBatis)-Spring中的Bean 通过Spring容器创建一个Bean的实例时,不仅可以完成 ...
- Mybatis执行流程学习之手写mybatis雏形
Mybatis是目前开发中最常用的一款基于ORM思想的半自动持久层框架,平时我们都仅仅停留在使用阶段,对mybatis是怎样运行的并不清楚,今天抽空找到一些资料自学了一波,自己写了一个mybatis的 ...
- 打包遇到错误Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test
引自:https://blog.csdn.net/xiexiangyan/article/details/107936774 遇到的问题 有一个maven项目,我clone一下最新的代码.准备打包(m ...
- 初次使用Open Live Writer
关于下载和配置 建议大家不要在官网下载,会出不来.华军软件园(或其他下载站)也提供Open Live Writer最新版的下载. 创建账户时千万不要写错地址,错一个就失败. 体验 体验还是很好的,美中 ...