藏宝图

藏宝图

时间限制: 2 Sec  内存限制: 256 MB
提交: 76  解决: 31
[提交][状态][讨论版]

题目描述

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\n");
 85             printf("1\n");
 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\n");
111         }
112         else{
113             printf("Yes\n");
114             printf("%d\n",sc);
115         }
116     }
117     return 0;
118 }
时间: 2024-10-23 04:39:24

藏宝图的相关文章

藏宝图题解

题目描述 Czy爬上黑红树,到达了一个奇怪的地方-- Czy发现了一张奇怪的藏宝图.图上有n个点,m条无向边.已经标出了图中两两之间距离dist.但是czy知道,只有当图刚好又是一颗树的时候,这张藏宝图才是真的.如果藏宝图是真的,那么经过点x的边的边权平均数最大的那个x是藏着宝物的地方.请计算这是不是真的藏宝图,如果是真的藏宝之处在哪里. 输入 输入数据第一行一个数T,表示T组数据. 对于每组数据,第一行一个n,表示藏宝图上的点的个数. 接下来n行,每行n个数,表示两两节点之间的距离. 输出 输

BZOJ 1560 火星藏宝图(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1560 题意: 思路:f[i]表示到达i的最大收益.这样是 O(n^2)的.我们考虑,由于转移的条件,a^2+b^2<(a+b)^2,因此对于三个点A.B.C.若A能到B,B能到C,那么A也能到C, 但是不如经过B更好.因此,我们记录到达第j列最靠下的i即可.那么转移(x,y)时,用记录的前y列即可. struct node { int x,y,w; }; node a[N]; int

【BZOJ1560】【JSOI2009】火星藏宝图 [DP]

火星藏宝图 Time Limit: 10 Sec  Memory Limit: 64 MB[Submit][Status][Discuss] Description Input Output Sample Input 4 10 1 1 20 10 10 10 3 5 60 5 3 30 Sample Output -4 HINT 1<= M <=2000, 2<= N <=100000. Main idea 每个点上有一个收益,从一个点走到另外一个点的花费是欧几里得距离的平方,问从

[NowCoder] 藏宝图

---恢复内容开始--- 牛牛拿到了一个藏宝图,顺着藏宝图的指示,牛牛发现了一个藏宝盒,藏宝盒上有一个机关,机关每次会显示两个字符串 s 和 t,根据古老的传说,牛牛需要每次都回答 t 是否是 s 的子序列.注意,子序列不要求在原字符串中是连续的,例如串 abc,它的子序列就有 {空串, a, b, c, ab, ac, bc, abc} 8 种. 输入描述: 每个输入包含一个测试用例.每个测试用例包含两行长度不超过 10 的不包含空格的可见 ASCII 字符串. 输出描述: 输出一行 "Yes

【noip模拟题】藏宝图(prim)

好神的一题.. 一开始没想多久就看题解了QAQ.. 首先我们发现,这棵树任意两个点的边一定是最小的(即所有其它这两个点的路径都比这条边大,才有可能出解) 然后生成树后再算距离判断即可.. 注意特判n=1.................. 还有出题人一点都不良心...说好的0<=dist[i][j]<=10^9呢...搞得我爆了好几次..... #include <cstdio> #include <cstring> #include <cmath> #in

[遇见时光]内推笔试-藏宝图-java实现

牛牛拿到了一个藏宝图,顺着藏宝图的指示,牛牛发现了一个藏宝盒,藏宝盒上有一个机关,机关每次会显示两个字符串 s 和 t,根据古老的传说,牛牛需要每次都回答 t 是否是 s 的子序列.注意,子序列不要求在原字符串中是连续的,例如串 abc,它的子序列就有 {空串, a, b, c, ab, ac, bc, abc} 8 种. 输入描述: 每个输入包含一个测试用例.每个测试用例包含两行长度不超过 10 的不包含空格的可见 ASCII 字符串. 输出描述: 输出一行 “Yes” 或者 “No” 表示结

2014.10.31我出的模拟赛【藏宝图】

藏宝图(treas.*) 背景 Czy爬上黑红树,到达了一个奇怪的地方…… 题目描述 Czy发现了一张奇怪的藏宝图.图上有n个点,m条无向边.已经标出了图中两两之间距离dist.但是czy知道,只有当图刚好又是一颗树的时候,这张藏宝图才是真的.如果藏宝图是真的,那么经过点x的边的边权平均数最大的那个x是藏着宝物的地方.请计算这是不是真的藏宝图,如果是真的藏宝之处在哪里. 格式 输入数据第一行一个数T,表示T组数据. 对于每组数据,第一行一个n,表示藏宝图上的点的个数. 接下来n行,每行n个数,表

一张游览PHP内核迷宫的藏宝图

PHP内核就像一个迷宫,如果没有一个纵览全局的图,只是面对其中的一个点,就会像进了迷宫一样,走着走着就走到了死胡同.在这个迷宫里转悠了很久之后,最近得到了一张PHP藏宝图,然后看着这张图去游览PHP内核,顿时觉得这个景区的面貌清晰了许多.废话不说了,上图: 这张图包括两部分,分别对应PHP的启动过程,和PHP处理每个请求的过程.PHP的启动过程是一系列的初始化操作,建立处理请求时使用的各种全局变量: Apache启动 => sapi_startup => php_module_startup

计蒜客 藏宝图

题目链接:藏宝图 说两种解法. 1.由于十个点都要走一次,所以可以枚举10个藏宝点的全排列,再把起点$(0,0)$和终点$(0,0)$放在排列的首尾,用11次bfs即可获得一种走法的最短路径. 2.把用二进制来表示每个藏宝点,$(x,y,status)$表示获得了status的宝物,来到了点$(x,y)$ 贴出位压代码: #include <stdio.h> #include <string.h> #include <queue> #include <algori