zoukankan      html  css  js  c++  java
  • 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],这样就是不符合条件的.


    #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
    ");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
    ");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
    ");
            else printf("MAGIC
    ");
        }
        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
    ");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
    ");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
    ");
            else printf("NOT MAGIC
    ");
        }
        return 0;
    }
    


  • 相关阅读:
    使用Dagger2做静态注入, 对比Guice.
    利用Cglib实现AOP
    Guice之IOC教程
    layui使用心得
    Protocol Buffer序列化对比Java序列化.
    IE之页面加载慢.
    浏览器Agent大全 (含IE 11, Edge)
    ASpectJ对AOP的实现
    Spring之AOP
    创建自己的加密货币MNC——以太坊代币(二)
  • 原文地址:https://www.cnblogs.com/herumw/p/9464534.html
Copyright © 2011-2022 走看看