藏宝图

 藏宝图

时间限制: 2 Sec  内存限制: 256 MB

题目描述

Czy爬上黑红树,到达了一个奇怪的地方……

Czy发现了一张奇怪的藏宝图。图上有n个点,m条无向边。已经标出了图中两两之间距离dist。但是czy知道,只有当图刚好又是一颗树的时候,这张藏宝图才是真的。如果藏宝图是真的,那么经过点x的边的边权平均数最大的那个x是藏着宝物的地方。请计算这是不是真的藏宝图,如果是真的藏宝之处在哪里。


输入

输入数据第一行一个数T,表示T组数据。

对于每组数据,第一行一个n,表示藏宝图上的点的个数。

接下来n行,每行n个数,表示两两节点之间的距离。

输出

输出一行或两行。第一行”Yes”或”No”,表示这是不是真的藏宝图。

若是真的藏宝图,第二行再输出一个数,表示哪个点是藏宝之处。

样例输入

2
3
0 7 9
7 0 2
9 2 0
3
0 2 7
2 0 9
7 9 0

样例输出

Yes
1
Yes
3

样例解释:第一棵树的形状是1--2--3。1、2之间的边权是7,2、3之间是2。
 第二棵树的形状是2--1--3。2、1之间的边权是2,1、3之间是7。

提示


对于30%数据,n<=50,1<=树上的边的长度<=10^9。



对于50%数据,n<=600.



对于100%数据,1<=n<=2500,除30%小数据外任意0<=dist[i][j]<=10^9,T<=5

   开始就没看懂题目,以为题目中给的是两个点之间直接连边的边权,然后就一直想不出来怎么着就不是一棵树,但其实图中给的是两个点之间的距离,那么,如果他是一棵树的话,这个距离是一定的,不可能存在更短的路径,因为在树中,两个点之间的路径是唯一的,若两个点之间的路径能被其他的点更新,那么就不是一棵树,因为两个点之间存在两条长度不同的路径,那么用prim跑一遍,得出最小生成树,在用这棵树去还原一个新的矩阵,若和原来的矩阵同,则yes,否则no,至于是某个点,随便搞都行

    因为这道题点数比较少,而边很密,所以用Kruska会被卡

  1 #include<cmath>
  2 #include<ctime>
  3 #include<cstdio>
  4 #include<cstdlib>
  5 #include<cstring>
  6 #include<iostream>
  7 #include<algorithm>
  8 using namespace std;
  9 int T,n;
 10 long long dis[2510][2510];
 11 long long ju[2510];
 12 bool vis[2510];
 13 int fa[2510];
 14 struct node{
 15     int u,v,nxt,w;
 16 }g[5010];
 17 int adj[5010],e;
 18 void add(int u,int v,int w){
 19     g[++e].v=v; g[e].u=u; g[e].w=w;
 20     g[e].nxt=adj[u]; adj[u]=e;
 21 }
 22 void prim(){
 23     ju[1]=0;
 24     for(int i=1;i<=n;i++){
 25         int k=0;
 26         for(int j=1;j<=n;j++){
 27             if(!vis[j] && ju[j]<ju[k])
 28                 k=j;
 29         }
 30         vis[k]=1;
 31         for(int j=1;j<=n;j++){
 32             if(!vis[j] && dis[k][j]<ju[j])
 33                 ju[j]=dis[k][j],fa[j]=k;
 34         }
 35     }
 36 }
 37 long long dis2[2510][2510],ji;
 38 double mx=0;
 39 int sc;
 40 void clear(){
 41     memset(vis,0,sizeof(vis));
 42     memset(ju,0x7f,sizeof(ju));
 43     //cout<<ju[1]<<endl;;
 44     memset(fa,0,sizeof(fa));
 45     e=0; mx=0;
 46     memset(adj,0,sizeof(adj));
 47      
 48 }
 49 void dfs(int x,long long sum,int num){
 50     //cout<<"ji== "<<ji<<"  "<<x<<" "<<sum<<" "<<num<<endl;
 51     dis2[ji][x]=sum;
 52     vis[x]=1;
 53     int chu;
 54     if(x==ji) chu=0;
 55     else chu=1;
 56     double he=(double)num;
 57     for(int i=adj[x];i;i=g[i].nxt){
 58         int v=g[i].v;
 59         if(vis[v]) continue;
 60         chu++;
 61         dfs(v,sum+g[i].w,g[i].w);
 62         he+=g[i].w;
 63     }
 64     he=he/(double)chu;
 65     if(he>mx){
 66         mx=he;
 67         sc=x;
 68     }
 69 }
 70 int main(){
 71     //freopen("a.in","r",stdin);
 72     //freopen("a.out","w",stdout);
 73     scanf("%d",&T);
 74     while(T--){
 75         scanf("%d",&n);
 76         clear();
 77         for(int i=1;i<=n;i++){
 78             for(int j=1;j<=n;j++){
 79                 scanf("%lld",&dis[i][j]);
 80                 //cout<<dis[i][j]<<endl;
 81             }
 82         }
 83         if(n==1){
 84             printf("Yes
");
 85             printf("1
");
 86             continue;
 87         }
 88         prim();
 89         for(int i=2;i<=n;i++){
 90             add(fa[i],i,ju[i]);
 91             add(i,fa[i],ju[i]);
 92         }
 93         /*
 94         for(int i=1;i<=n;i++){
 95             cout<<"i== "<<i<<" "<<fa[i]<<endl;
 96         }*/
 97         for(int i=1;i<=n;i++){
 98             memset(vis,0,sizeof(vis));
 99             vis[i]=1; ji=i;
100             dfs(i,0,0);
101         }
102         //while(1);
103         bool ok=1;
104         for(int i=1;i<=n;i++){
105             for(int j=1;j<=n;j++){
106                 if(dis2[i][j] != dis[i][j]) ok=0;
107             }
108         }
109         if(!ok){
110             printf("No
");
111         }
112         else{
113             printf("Yes
");
114             printf("%d
",sc);
115         }
116     }
117     return 0;
118 }
原文地址:https://www.cnblogs.com/FOXYY/p/7258161.html