Codeforces #270 D. Design Tutorial: Inverse the Problem

D. Design Tutorial: Inverse the Problem
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

There is an easy way to obtain a new task from an old one called "Inverse the problem": we give an output of the original task, and ask to generate an input, such that solution to the original problem will produce the output we provided. The hard task of Topcoder Open 2014 Round 2C, InverseRMQ, is a good example.

Now let's create a task this way. We will use the task: you are given a tree, please calculate the distance between any pair of its nodes. Yes, it is very easy, but the inverse version is a bit harder: you are given an n × n distance matrix. Determine if it is the distance matrix of a weighted tree (all weights must be positive integers).

Input

The first line contains an integer n (1 ≤ n ≤ 2000) — the number of nodes in that graph.

Then next n lines each contains n integers di, j (0 ≤ di, j ≤ 109) — the distance between node i and node j.

Output

If there exists such a tree, output "YES", otherwise output "NO".

Sample test(s)
input
3
0 2 7
2 0 9
7 9 0
output
YES
input
3
1 2 7
2 0 9
7 9 0
output
NO
input
3
0 2 2
7 0 9
7 9 0
output
NO
input
3
0 1 1
1 0 1
1 1 0
output
NO
input
2
0 0
0 0
output
NO
 
给出一个矩阵,表示两个点之间的距离,判断这些点能否构成一颗树。。

1th:构造最小生成树。

    我们提取所有的边出来按边排序,因为每次我们知道边的权值>0,

之后每次把边加入集合中,不断构造,类似  kruskal算法,构造出边后

再对每个点进行整张图的DFS求距离

复杂度O(N^2lgN):对所有边排序的复杂度。

 

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<algorithm>
  6 #include<vector>
  7 using namespace std;
  8 
  9 int n;
 10 int nu[2006][2006];
 11 int fa[2006];
 12 int ct = 0;
 13 
 14 struct edge
 15 {
 16     int x,y,w;
 17     edge(int x = 0,int y = 0,int w = 0):x(x),y(y),w(w){}
 18     bool operator <(const edge &rhs) const
 19     {
 20         return w<rhs.w;
 21     }
 22 }eg[2006*2006];
 23 
 24 vector<int> g[2006];
 25 
 26 int find(int x) {
 27  if(x==fa[x]) return x;
 28  else return fa[x] = find(fa[x]);
 29 }
 30 
 31 int node;
 32 int flag= 0;
 33 
 34 int kruskal()
 35 {
 36     sort(eg,eg+ct);
 37     for(int i = 0;i<n;i++) fa[i] = i;
 38     for(int i = 0;i<ct;i++)
 39     {
 40         int tx = find(eg[i].x);
 41         int ty = find(eg[i].y);
 42         if(tx!=ty)
 43         {
 44             fa[tx] = ty;
 45             g[eg[i].x].push_back(eg[i].y);
 46             g[eg[i].y].push_back(eg[i].x);
 47             //cout<<eg[i].x<<' '<<eg[i].y<<' '<<eg[i].w<<'?'<<endl;
 48         }
 49     }
 50 }
 51 
 52 int dfs(int v,int now,int fa)
 53 {
 54     for(int i = 0;i<g[v].size();i++)
 55     {
 56         int t = g[v][i];
 57         if(t == fa) continue;
 58         //cout<<node<<' '<<t<<' '<<nu[v][t]+now<<endl;
 59         int wt = nu[v][t]+now;
 60         if(nu[node][t]!=wt) {flag = 1;return -1;}
 61         else
 62           dfs(t,wt,v);
 63     }
 64     return 0;
 65 }
 66 
 67 int main()
 68 {
 69     scanf("%d",&n);
 70     int num;
 71     for(int i = 0;i<n;i++) g[i].clear();
 72     for(int i = 0;i<n;i++)
 73      for(int j = 0;j<n;j++)
 74     {
 75         scanf("%d",&num);
 76         nu[i][j] = num;
 77         if(i>j)
 78         {
 79             eg[ct].x = i;
 80             eg[ct].y = j;
 81             eg[ct++].w = num;
 82         }
 83         if(nu[i][j]!=0&&i==j) flag = 1;
 84         if(j<i&&nu[i][j]!=nu[j][i]) flag = 1;
 85         if(nu[i][j]==0&&i!=j) flag = 1;
 86     }
 87     if(flag!=1)
 88     {
 89     kruskal();
 90     for(int i = 0;i<n;i++)
 91     {
 92         node = i;
 93         if(dfs(i,0,-1)==-1) {flag = 1; break;}
 94     }
 95     }
 96     if(flag == 1) puts("NO");
 97     else puts("YES");
 98   return 0;
 99 }
100 /*
101 7
102 0 1 1 2 2 3 3
103 1 0 2 1 3 2 4
104 1 2 0 3 1 4 2
105 2 1 3 0 4 1 5
106 2 3 1 4 0 5 1
107 3 2 4 1 5 0 6
108 3 4 2 5 1 6 0
109 */

第二种做法不得不佩服!1

这个特种点很难在比赛中发现啊

关键点:我们知道一个点到其他所有点都有一条最小距离的边--假设A到其他点最小距离的点是B,A-B一定是直接连接的。假设距离是X。

           然后假设一个点C,C到B点要么比C到A点近X,要么C到A点远X。具体可以画图。

通过这个方法可以判断数据是否合法!

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 int num[2060][2060];
 9 int n;
10 
11 int main()
12 {
13     scanf("%d",&n);
14     for(int i = 0;i<n;i++)
15         for(int j = 0;j<n;j++)
16     {
17         scanf("%d",&num[i][j]);
18     }
19     int flag = 0;
20     for(int i = 0;i<n;i++)
21         for(int j = i;j<n;j++)
22     {
23         if(num[i][j]!=0&&i==j) flag = 1;
24         if(num[i][j]!=num[j][i]) flag = 1;
25         if(num[i][j]==0&&i!=j) flag = 1;
26     }
27 
28     for(int i = 0;i<n;i++)
29     {
30         int inf = 1000000006;
31         int pos = -1;
32         for(int j = 0;j<n;j++)
33         {
34             if(i==j) continue;
35             if(num[i][j]<inf)
36             {
37                 inf = num[i][j];
38                 pos = j;
39             }
40         }
41 
42         for(int j = 0;j<n;j++)
43         {
44            if(j==i||j==pos) continue;
45            if(abs(num[i][j]-num[pos][j])!=inf)
46                 flag = 1;
47         }
48     }
49     if(flag == 1) puts("NO");
50     else puts("YES");
51     return 0;
52 }

 

posted @ 2014-10-19 19:11  haohaooo  阅读(255)  评论(0编辑  收藏  举报