1. 程式人生 > >(最小生成樹)Codeforces Educational Codeforces Round 9 Magic Matrix

(最小生成樹)Codeforces Educational Codeforces Round 9 Magic Matrix

屬於 while 數組 write call pre rar matrix ring

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\n");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\n");
182         else
183             printf("NOT MAGIC\n");
184     }
185 }

(最小生成樹)Codeforces Educational Codeforces Round 9 Magic Matrix