zoukankan      html  css  js  c++  java
  • (最小生成树)Codeforces Educational Codeforces Round 9 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 use scanf/printf instead of cin/cout in C++, prefer to use BufferedReader/PrintWriter instead of Scanner/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".

    Example

    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

    定义中的前两个条件直接检验即可,对于第三个条件等价于从i到j的任意路径的最大值的最小值与a[i][j]最小。

    利用kruskal中利用的性质,每次选的都是最小的边,故i到j上述的值一定是在最小生成树中最小。
    故只需要先生成最小生成树,再算出此时的任意i与j间“任意路径的最大值的最小值”,与a[i][j]逐个比较即可。

      1 #include <iostream>
      2 #include <string>
      3 #include <algorithm>
      4 #include <cstring>
      5 #include <cstdio>
      6 #include <cmath>
      7 #include <queue>
      8 #include <set>
      9 #include <map>
     10 #include <list>
     11 #include <vector>
     12 #include <stack>
     13 #define mp make_pair
     14 #define MIN(a,b) (a>b?b:a)
     15 #define rank rankk
     16 //#define MAX(a,b) (a>b?a:b)
     17 typedef long long ll;
     18 typedef unsigned long long ull;
     19 const int MAX=2505;
     20 const ll INF=1e18+5;
     21 const int B=1024;//桶的大小
     22 const double M=4e18;
     23 using namespace std;
     24 const int MOD=1e9+7;
     25 typedef pair<int,int> pii;
     26 int n,cnt;
     27 int a[MAX][MAX];
     28 bool vi[MAX];
     29 vector <int> road[MAX];
     30 bool res;
     31 int mst[MAX][MAX];
     32 
     33 /*
     34     kruskal最小生成树算法
     35     按照边的权值的顺序从小到大看一遍,如果不产生圈(重边也考虑在内)
     36     就把当前这条边加入到生成树中
     37     是否产生圈只需看两点之前是否在同一连通分量里
     38     使用并查集判断是否属于同一个连通分量
     39 */
     40 #define rank rankk  //由于与某个库名称相同,故事先define
     41 /*
     42 并查集
     43 复杂度为阿克曼函数的反函数,比O(log(n))还快
     44 */
     45 
     46 int par[MAX];//父亲
     47 int rank[MAX];//树的高度
     48 //初始化n个元素
     49 void init(int n)
     50 {
     51     for(int i=0;i<n;i++)
     52     {
     53         par[i]=i;
     54         rank[i]=0;
     55     }
     56 }
     57 //查询树的根,期间加入了路径压缩
     58 int find(int x)
     59 {
     60     if(par[x]==x)
     61         return x;
     62     else
     63         return par[x]=find(par[x]);
     64 }
     65 //合并x和y所属的集合
     66 void unite(int x,int y)
     67 {
     68     x=find(x);
     69     y=find(y);
     70     if(x==y)
     71         return ;
     72     if(rank[x]<rank[y])
     73         par[x]=y;
     74     else
     75     {
     76         par[y]=x;
     77         if(rank[x]==rank[y])
     78             rank[x]++;
     79     }
     80 }
     81 //判断x和y是否属于同一个集合
     82 bool same(int x,int y)
     83 {
     84     return find(x)==find(y);
     85 }
     86 /*
     87 建立结构体记录边
     88 */
     89 struct edge
     90 {
     91     int u,v,cost;
     92 };
     93 /*储存边的数组*/
     94 edge es[MAX*MAX/2];
     95 int V,E;//顶点数、边数
     96 bool cmp(const edge &e1,const edge &e2)
     97 {
     98     return e1.cost<e2.cost;
     99 }
    100 void kruskal(edge *e,int edge_num,int vertice_num)//e为存储边的数组,下标从0开始
    101 {
    102     sort(e,e+edge_num,cmp);//按照edge.cost顺序从小到大排序
    103     init(vertice_num+2);//初始化并查集
    104     for(int i=1;i<=vertice_num;i++)
    105         road[i].clear();
    106 //    ll re=0;
    107     for(int i=0;i<edge_num;i++)
    108     {
    109         edge tem=e[i];
    110         if(!same(tem.u,tem.v))
    111         {
    112             road[tem.u].push_back(tem.v);
    113             road[tem.v].push_back(tem.u);
    114             unite(tem.u,tem.v);
    115 //            re+=(ll)tem.cost;
    116         }
    117     }
    118 //    return re;
    119 }
    120 void dfs(int lo,int st,int nowmax)
    121 {
    122     vi[lo]=true;
    123     mst[st][lo]=nowmax;
    124     for(int i=0;i<road[lo].size();i++)
    125     {
    126         int to=road[lo][i];
    127         if(!vi[to])
    128             dfs(to,st,max(nowmax,a[lo][to]));
    129     }
    130 }
    131 bool check1(int x)
    132 {
    133     for(int i=1;i<=x;i++)
    134         if(a[i][i])
    135             return false;
    136     for(int i=1;i<=x;i++)
    137         for(int j=i+1;j<=x;j++)
    138             if(a[i][j]!=a[j][i])
    139                 return false;
    140     return true;
    141 }
    142 int main()
    143 {
    144     while(~scanf("%d",&n))
    145     {
    146         res=true;
    147         cnt=0;
    148         edge tem;
    149         for(int i=1;i<=n;i++)
    150             for(int j=1;j<=n;j++)
    151                 {
    152                     scanf("%d",&a[i][j]);
    153                     if(j>i)
    154                     {
    155                         tem.u=i;tem.v=j;tem.cost=a[i][j];es[cnt++]=tem;
    156                     }
    157                 }
    158         if(!check1(n))
    159         {
    160             printf("NOT MAGIC
    ");continue;
    161         }
    162         kruskal(es,cnt,n);
    163         for(int i=1;i<=n;i++)
    164         {
    165             memset(vi,false,sizeof(vi));
    166             dfs(i,i,0);
    167         }
    168         for(int i=1;i<=n;i++)
    169         {
    170             for(int j=1;j<=n;j++)
    171             {
    172                 if(mst[i][j]!=a[i][j])
    173                     res=false;
    174                 if(!res)
    175                     break;
    176             }
    177             if(!res)
    178                 break;
    179         }
    180         if(res)
    181             printf("MAGIC
    ");
    182         else
    183             printf("NOT MAGIC
    ");
    184     }
    185 }
  • 相关阅读:
    调整压力测试工具转载ibm
    Python装饰器的使用
    python操作mysql数据库
    python进程与线程的操作
    python selenium框架的Xpath定位元素
    在Ubuntu Server 12.04 x64下安装Graphite
    SQLCLR(一)入门
    DataSet操作
    ASP.NET传递中文参数乱码的解决方法
    c#.net常用函数和方法集
  • 原文地址:https://www.cnblogs.com/quintessence/p/6906523.html
Copyright © 2011-2022 走看看