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.

Input

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.

Output

Print ''MAGIC" (without quotes) if the given matrix A is magic. Otherwise print ''NOT MAGIC".

Examples
input
3
0 1 2
1 0 2
2 2 0
output
MAGIC
input
2
0 1
2 3
output
NOT MAGIC
input
4
0 1 2 3
1 0 3 4
2 3 0 5
3 4 5 0
output

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],这样就是不符合条件的.


[cpp]  view plain  copy
  1. #include<iostream>  
  2. #include<stdio.h>  
  3. #include<stdlib.h>  
  4. #include<string.h>  
  5. #include<math.h>  
  6. #include<vector>  
  7. #include<map>  
  8. #include<set>  
  9. #include<queue>  
  10. #include<stack>  
  11. #include<string>  
  12. #include<bitset>  
  13. #include<algorithm>  
  14. using namespace std;  
  15. typedef long long ll;  
  16. typedef long double ldb;  
  17. #define inf 99999999  
  18. #define pi acos(-1.0)  
  19. #define maxn 2505  
  20. int a[maxn][maxn];  
  21. struct node{  
  22.     int len,l,r;  
  23. }e[maxn*maxn/2];  
  24.   
  25. bool cmp(node a,node b){  
  26.     return a.len<b.len;  
  27. }  
  28. bitset<maxn>bt[maxn];  
  29. int main()  
  30. {  
  31.     int n,m,i,j,flag;  
  32.     while(scanf("%d",&n)!=EOF)  
  33.     {  
  34.         flag=1;  
  35.         int tot=0;  
  36.         for(i=1;i<=n;i++){  
  37.             for(j=1;j<=n;j++){  
  38.                 scanf("%d",&a[i][j]);  
  39.                 if(i<j){  
  40.                     tot++;  
  41.                     e[tot].len=a[i][j];  
  42.                     e[tot].l=i;e[tot].r=j;  
  43.                 }  
  44.             }  
  45.         }  
  46.         for(i=1;i<=n;i++){  
  47.             if(a[i][i]!=0){  
  48.                 flag=0;break;  
  49.             }  
  50.         }  
  51.         if(flag==0){  
  52.             printf("NOT MAGIC\n");continue;  
  53.         }  
  54.         for(i=1;i<=n;i++){  
  55.             for(j=i+1;j<=n;j++){  
  56.                 if(a[i][j]!=a[j][i]){  
  57.                     flag=0;break;  
  58.                 }  
  59.             }  
  60.             if(!flag)break;  
  61.         }  
  62.         if(flag==0){  
  63.             printf("NOT MAGIC\n");continue;  
  64.         }  
  65.         sort(e+1,e+1+tot,cmp);  
  66.         int t=1;  
  67.         for(i=1;i<=tot;i++){  
  68.              while(t<=tot && e[t].len<e[i].len ){  
  69.                 bt[e[t].l ][e[t].r ]=1;  
  70.                 bt[e[t].r ][e[t].l ]=1;  
  71.                 t++;  
  72.              }  
  73.              if((bt[e[i].l ]&bt[e[i].r ] ).any() ){  
  74.                 flag=0;break;  
  75.              }  
  76.         }  
  77.         if(flag==0)printf("NOT MAGIC\n");  
  78.         else printf("MAGIC\n");  
  79.     }  
  80.     return 0;  
  81. }  

第二种思路:是把这个矩阵看做一张图,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一遍所有点,记录根到其他所有点的最小生成树路径中的最小边就行了.


[cpp]  view plain  copy
  1. #include<iostream>  
  2. #include<stdio.h>  
  3. #include<stdlib.h>  
  4. #include<string.h>  
  5. #include<math.h>  
  6. #include<vector>  
  7. #include<map>  
  8. #include<set>  
  9. #include<queue>  
  10. #include<stack>  
  11. #include<string>  
  12. #include<algorithm>  
  13. #define inf 99999999  
  14. #define pi acos(-1.0)  
  15. #define maxn 2505  
  16. #define MOD 1000000007  
  17. using namespace std;  
  18. typedef long long ll;  
  19. typedef long double ldb;  
  20. int a[maxn][maxn];  
  21. struct node{  
  22.     int len,l,r;  
  23. }e[maxn*maxn/2];  
  24. int pre[maxn],ran[maxn],num[maxn],maxx[maxn];  
  25. struct edg{  
  26.     int next,to,len;  
  27. }edge[2*maxn];  
  28. int first[maxn];  
  29.   
  30. int findset(int x){  
  31.     int i,j=x,r=x;  
  32.     while(r!=pre[r])r=pre[r];  
  33.     while(j!=pre[j]){  
  34.         i=pre[j];  
  35.         pre[j]=r;  
  36.         j=i;  
  37.     }  
  38.     return r;  
  39. }  
  40. bool cmp(node a,node b){  
  41.     return a.len<b.len;  
  42. }  
  43. int flag;  
  44. void dfs(int u,int father,int x)  
  45. {  
  46.     int i,j,v;  
  47.     for(i=first[u];i!=-1;i=edge[i].next){  
  48.         v=edge[i].to;  
  49.         if(v==father)continue;  
  50.         maxx[v]=max(maxx[u],edge[i].len);  
  51.         if(a[x][v]!=maxx[v]){  
  52.             flag=0;break;  
  53.         }  
  54.         dfs(v,u,x);  
  55.         if(flag==0)break;  
  56.     }  
  57. }  
  58. int main()  
  59. {  
  60.     int n,m,i,j;  
  61.     while(scanf("%d",&n)!=EOF)  
  62.     {  
  63.         flag=1;  
  64.         int tot=0;  
  65.         for(i=1;i<=n;i++){  
  66.             pre[i]=i;ran[i]=0;num[i]=1;  
  67.             for(j=1;j<=n;j++){  
  68.                 scanf("%d",&a[i][j]);  
  69.                 if(i<j){  
  70.                     tot++;  
  71.                     e[tot].len=a[i][j];  
  72.                     e[tot].l=i;e[tot].r=j;  
  73.                 }  
  74.             }  
  75.         }  
  76.         for(i=1;i<=n;i++){  
  77.             if(a[i][i]!=0){  
  78.                 flag=0;break;  
  79.             }  
  80.         }  
  81.         if(flag==0){  
  82.             printf("NOT MAGIC\n");continue;  
  83.         }  
  84.         for(i=1;i<=n;i++){  
  85.             for(j=i+1;j<=n;j++){  
  86.                 if(a[i][j]!=a[j][i]){  
  87.                     flag=0;break;  
  88.                 }  
  89.             }  
  90.             if(!flag)break;  
  91.         }  
  92.         if(flag==0){  
  93.             printf("NOT MAGIC\n");continue;  
  94.         }  
  95.   
  96.         sort(e+1,e+1+tot,cmp);  
  97.         int t1,t2,u,v,x,y;  
  98.         int t=0;  
  99.         memset(first,-1,sizeof(first));  
  100.         for(i=1;i<=tot;i++){  
  101.             u=e[i].l;v=e[i].r;  
  102.             x=findset(u);  
  103.             y=findset(v);  
  104.             if(x==y)continue;  
  105.             t++;  
  106.             edge[t].next=first[u];edge[t].to=v;edge[t].len=a[u][v];  
  107.             first[u]=t;  
  108.   
  109.             t++;  
  110.             edge[t].next=first[v];edge[t].to=u;edge[t].len=a[u][v];  
  111.             first[v]=t;  
  112.   
  113.             if(ran[x]>ran[y]){  
  114.                 pre[y]=x;  
  115.                 num[x]+=num[y];  
  116.                 if(num[x]==n)break;  
  117.             }  
  118.             else{  
  119.                 pre[x]=y;  
  120.                 num[y]+=num[x];  
  121.                 if(num[y]==n)break;  
  122.                 if(ran[x]==ran[y])ran[y]++;  
  123.             }  
  124.         }  
  125.         for(j=1;j<=n;j++){  
  126.             maxx[j]=0;  
  127.             dfs(j,0,j);  
  128.             if(flag==0)break;  
  129.         }  
  130.         if(flag)printf("MAGIC\n");  
  131.         else printf("NOT MAGIC\n");  
  132.     }  
  133.     return 0;  
  134. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值