[关闭]
@ysner 2018-06-09T06:22:28.000000Z 字数 1911 阅读 1643

藏宝图

最小生成树 图论


题面

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

解析

光是判断是不是树就让我想半天。。。
当时我想的是,因为该图联通,所以给的距离中一定只有条是边,其它个距离都是边之和。
而且对于任意两点来说, 边之和 一定大于它们两个的任意一条邻边。(因为 边之和 起码由两条邻边构成)
所以对于任意两点,我们可以优先取相对于 边之和 值更小的邻边,保证了取距离小的边这一操作的正确性。
强上啊。
然后算两点距离(以一个点为根,就可以把到每个点的距离转化为深度)看是否符合来判断树。
接下来随便怎么搞都可以。
考场掉缘故:

  1. #include<iostream>
  2. #include<cmath>
  3. #include<cstring>
  4. #include<cstdio>
  5. #include<cstdlib>
  6. #include<algorithm>
  7. #define ll long long
  8. #define re register
  9. #define il inline
  10. #define eps 1e-9
  11. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  12. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  13. using namespace std;
  14. const int N=3000;
  15. ll dis[N][N],d[N];
  16. double mx;
  17. int pos,h[N],n,tot,cnt;
  18. struct Edge{int to,nxt;ll w;}e[N<<1];
  19. il void add(re int u,re int v,re ll w){e[++cnt]=(Edge){v,h[u],w};h[u]=cnt;}
  20. struct Dat
  21. {
  22. int u,v;ll w;
  23. bool operator < (const Dat &o) const {return w<o.w;}
  24. }a[N*N];
  25. int f[N];
  26. il void dfs(re int u,re int fa,re ll deep)
  27. {
  28. //printf("%d %d %lld\n",u,fa,deep);
  29. d[u]=deep;
  30. for(re int i=h[u];i+1;i=e[i].nxt)
  31. {
  32. re int v=e[i].to;
  33. if(v==fa) continue;
  34. dfs(v,u,deep+e[i].w);
  35. }
  36. }
  37. il int check()
  38. {
  39. fp(i,1,n)
  40. {
  41. dfs(i,0,0);
  42. fp(j,1,n) if(d[j]!=dis[i][j]) return 0;
  43. }
  44. return 1;
  45. }
  46. il int find(re int x){return x==f[x]?x:f[x]=find(f[x]);}
  47. int main()
  48. {
  49. freopen("treas.in","r",stdin);
  50. freopen("treas.out","w",stdout);
  51. re int T=gi();
  52. while(T--)
  53. {
  54. n=gi();tot=0;
  55. fp(i,1,n)
  56. {
  57. f[i]=i;
  58. fp(j,1,n)
  59. {
  60. dis[i][j]=gi();
  61. if(i<j) a[++tot]=(Dat){i,j,dis[i][j]};
  62. }
  63. }
  64. sort(a+1,a+1+tot);
  65. memset(h,-1,sizeof(h));cnt=0;
  66. fp(i,1,tot)
  67. {
  68. re int u=a[i].u,v=a[i].v,fu=find(u),fv=find(v);ll w=a[i].w;
  69. //printf("%d %d %d %d %d %lld\n",i,u,v,fu,fv,w);
  70. if(fu==fv) continue;
  71. add(u,v,w);add(v,u,w);
  72. f[fu]=fv;
  73. }
  74. if(!check()) {puts("No");continue;}else puts("Yes");
  75. mx=-1e18;pos=1;
  76. fp(i,1,n)
  77. {
  78. re ll sum=0,ysn=0;
  79. for(re int j=h[i];j+1;j=e[j].nxt)
  80. {
  81. re int v=e[j].to;
  82. sum+=e[j].w;++ysn;
  83. }
  84. if(1.0*sum/ysn+eps>mx) mx=1.0*sum/ysn,pos=i;
  85. }
  86. printf("%d\n",pos);
  87. }
  88. fclose(stdin);
  89. fclose(stdout);
  90. return 0;
  91. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注