藏宝图
Posted A_LEAF
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了藏宝图相关的知识,希望对你有一定的参考价值。
背景
Czy 爬上黑红树,到达了一个奇怪的地方……
题目描述
Czy 发现了一张奇怪的藏宝图。图上有n 个点,m 条无向边。已经标出了图中两两之
间距离dist。但是czy 知道,只有当图刚好又是一颗树的时候,这张藏宝图才是真的。如
果藏宝图是真的,那么经过点x 的边的边权平均数最大的那个x 是藏着宝物的地方。请计
算这是不是真的藏宝图,如果是真的藏宝之处在哪里。
格式
输入数据第一行一个数T,表示T 组数据。
对于每组数据,第一行一个n,表示藏宝图上的点的个数。
接下来n 行,每行n 个数,表示两两节点之间的距离。
输出一行或两行。第一行”Yes”或”No”,表示这是不是真的藏宝图。
若是真的藏宝图,第二行再输出一个数,表示哪个点是藏宝之处。
样例输入
230
7 9
7 0 2
9 2 0
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
solution:
树的性质:有n个点,n-1条边。
给的矩阵不是树,就是图
先跑一边最小生成树,再用O(n^2)求出最小生成树上各点之间的距离,得到一个新的矩阵
再将新得到的矩阵与原来的 进行对比,如果不同,说明是图
至于最小生成树,这题卡kruskar的O(n^2*logn),用prim O(n^2)
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<cmath> 5 #include<algorithm> 6 #define ll long long 7 #define mem(a,b) memset(a,b,sizeof(a)) 8 #define dd double 9 using namespace std; 10 int read() 11 { 12 int ans=0;char q=getchar(); 13 while(q<‘0‘||q>‘9‘)q=getchar(); 14 while(q>=‘0‘&&q<=‘9‘){ans=ans*10+q-‘0‘;q=getchar();} 15 return ans; 16 } 17 18 int T; 19 int n; 20 ll a[2505][2505]; 21 ll d[2505]; 22 int vis[2505],qian[2505]; 23 ll a2[2505][2505]; 24 struct son1 25 { 26 int v,next; 27 ll w; 28 }; 29 son1 a1[10001]; 30 int first[10001],e; 31 void addbian(int u,int v,ll w) 32 { 33 a1[e].w=w; 34 a1[e].v=v; 35 a1[e].next=first[u]; 36 first[u]=e++; 37 } 38 39 void clear() 40 { 41 mem(d,0x7f); 42 mem(first,-1); 43 e=0; 44 mem(a1,0); 45 mem(a2,0); 46 mem(vis,0); 47 mem(qian,0); 48 } 49 50 void dfs(int fa,int x,int now) 51 { 52 for(int i=first[x];i!=-1;i=a1[i].next) 53 { 54 int temp=a1[i].v; 55 if(temp==fa)continue; 56 a2[now][temp]=a2[now][x]+a1[i].w; 57 dfs(x,temp,now); 58 } 59 } 60 61 void out11() 62 { 63 printf("\n\n"); 64 for(int i=1;i<=n;++i) 65 printf("%d ",qian[i]); 66 printf("\n\n"); 67 for(int i=1;i<=n;++i) 68 printf("%d ",d[i]); 69 printf("\n\n"); 70 for(int i=1;i<=n;++i) 71 { 72 for(int j=1;j<=n;++j) 73 printf("%d ",a[i][j]); 74 printf("\n"); 75 } 76 printf("\n"); 77 for(int i=1;i<=n;++i) 78 { 79 for(int j=1;j<=n;++j) 80 printf("%lld ",a2[i][j]); 81 printf("\n"); 82 } 83 printf("\n"); 84 } 85 86 int main(){ 87 //freopen("1.txt","r",stdin); 88 //freopen("treas1.in","r",stdin); 89 //freopen("treas.out","w",stdout); 90 T=read(); 91 while(T--) 92 { 93 int wrong=0; 94 scanf("%d",&n); 95 for(int i=1;i<=n;++i) 96 for(int j=1;j<=n;++j) 97 scanf("%lld",&a[i][j]); 98 //a[i][j]=read(); 99 100 for(int i=1;i<=n;++i) 101 if(a[i][i])wrong=1; 102 103 for(int i=1;i<=n;++i) 104 for(int j=i+1;j<=n;++j) 105 if(a[i][j]!=a[j][i]) 106 wrong=1; 107 108 if(wrong) 109 {printf("No\n");continue;} 110 111 clear(); 112 113 d[1]=0; 114 115 for(int i=1;i<=n;++i) 116 { 117 int k=0; 118 for(int j=1;j<=n;++j) 119 if(!vis[j]&&d[j]<d[k]) 120 k=j; 121 122 //printf("k=%d\n",k); 123 124 vis[k]=1; 125 for(int j=1;j<=n;++j) 126 if(!vis[j]&&a[k][j]<d[j]) 127 { 128 //printf("j=%d\n",j); 129 qian[j]=k; 130 d[j]=a[k][j]; 131 } 132 } 133 134 for(int i=2;i<=n;++i) 135 addbian(i,qian[i],d[i]),addbian(qian[i],i,d[i]); 136 137 for(int i=1;i<=n;++i) 138 dfs(-1,i,i); 139 140 //out11(); 141 142 for(int i=1;i<=n;++i) 143 { 144 if(wrong==1)break; 145 for(int j=1;j<=n;++j) 146 if(a[i][j]!=a2[i][j]) 147 {wrong=1;break;} 148 } 149 150 if(wrong) 151 {printf("No\n");continue;} 152 153 dd maxl=0; 154 int order; 155 for(int i=1;i<=n;++i) 156 { 157 dd sum=0;int ci=0; 158 for(int j=first[i];j!=-1;j=a1[j].next) 159 {sum+=a1[j].w;++ci;} 160 sum/=(dd)ci; 161 //printf("i=%d sum=%.4lf\n",i,sum); 162 if(sum>maxl){maxl=sum;order=i;} 163 } 164 165 166 printf("Yes\n%d\n",order); 167 } 168 //while(1); 169 return 0; 170 }
以上是关于藏宝图的主要内容,如果未能解决你的问题,请参考以下文章