• 藏宝图


    题目描述

    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

    【题解】

            考试的时候完全没有思路,想试试把多余边都拆掉能不能行,但是完全没有想起“最小生成树”这几个字眼。其实想想最小生成树,加有用的边不就相当于删无用的边吗?还是得懂得变通啊。

           稠密图卡克鲁斯卡尔是众所周知,而每两点之间都有边可算得上是最稠密不过的图了,复习普里姆,选择最近的点把它加入树。建出树之后dfs求各点到1的距离,lca求各两点之间距离,验证一下是否是树。是树不是树都好办,这题主要是步骤非常多,用了很多算法,调试有一定难度(我也不出意料地打得非常冗长)。思路上大概也只有最小生成树和稠密图比较困难吧。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #define ll long long
    using namespace std;
    const int sj=2505;
    ll ca,n,dist[sj][sj],dis[sj],mi;
    int e,xb[sj],lca[sj][sj],f[sj],zx,h[sj],fa[sj];
    bool r[sj],op;
    void init()
    {
         scanf("%d",&n);
         memset(dis,0x3f,sizeof(dis));
         memset(f,-1,sizeof(f));
         memset(h,-1,sizeof(h));
         memset(r,0,sizeof(r));
         for(int i=1;i<=n;i++)
         {
           for(int j=1;j<=n;j++)
             scanf("%lld",&dist[i][j]);
         }
    }
    struct B
    {
         int ne,v,w;
    }b[sj*2];
    void add(int x,int y,int z)
    {
         b[e].v=y;
         b[e].ne=h[x];
         b[e].w=z;
         h[x]=e++;
    }
    void mst()
    {
         memset(dis,0x3f,sizeof(dis));
         for(int i=1;i<=n;i++)
           if(dist[i][1]<dis[i])
           {
             dis[i]=dist[i][1];
             fa[i]=1;
           }
         r[1]=1;
         for(int i=1;i<=n-1;i++)
         {
            mi=0x7fffffff;
            zx=1;
            for(int j=1;j<=n;j++)
              if(!r[j]&&dis[j]<mi)
                mi=dis[j],zx=j;
            r[zx]=1;
            add(fa[zx],zx,dis[zx]);
            add(zx,fa[zx],dis[zx]);
            for(int j=1;j<=n;j++)
              if(!r[j]&&dist[zx][j]<dis[j])
              { 
                dis[j]=dist[zx][j];
                fa[j]=zx;
              }
         }
    }
    int find(int x)
    {
         if(f[x]==-1) return x;
         f[x]=find(f[x]);
         return f[x];
    }
    void hb(int x,int y)
    {
         x=find(x);
         y=find(y);
         if(x!=y)
           f[x]=y;
    }
    void dfs(int x)
    {
         r[x]=1;
         for(int i=h[x];i!=-1;i=b[i].ne)
           if(!r[b[i].v]&&b[i].v!=fa[x])
           {
             dis[b[i].v]=dis[x]+b[i].w;
             dfs(b[i].v);
           }
    }
    void tarjan(int x)
    {
         xb[x]=x;
         r[x]=1;
         for(int i=h[x];i!=-1;i=b[i].ne)
           if(!r[b[i].v])
           {
              tarjan(b[i].v);
              hb(x,b[i].v);
              xb[find(b[i].v)]=x;
           }
         for(int i=1;i<=n;i++)
           if(r[i])
             lca[i][x]=lca[x][i]=xb[find(i)];
    }
    int main()
    {
        //freopen("t3.txt","r",stdin);
        //freopen("treas9.in","r",stdin);
        //freopen("treas.out","w",stdout);
        scanf("%d",&ca);
        for(int l=1;l<=ca;l++)
        {
          init();
          mst();
          memset(r,0,sizeof(r));
          dfs(1);
          memset(r,0,sizeof(r));
          tarjan(1);
          op=1;
          for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
              if(dis[i]+dis[j]-2*dis[lca[i][j]]!=dist[i][j])
              {
                 op=0;
                 break;
              }
          if(!op) printf("No
    ");
          if(op)
          {
              printf("Yes
    ");
              double temp;
              int ge;
              mi=0;
              zx=1;
              for(int i=1;i<=n;i++)
              {
                ge=0;
                temp=0;
                for(int j=h[i];j!=-1;j=b[j].ne)
                {
                  temp+=abs(dis[i]-dis[b[j].v]);
                  ge++;
                }
                temp/=ge;
                if(temp>mi)
                {
                   mi=temp;
                   zx=i;
                }
              }
              printf("%d
    ",zx);
          }
        }
        //while(1);
        return 0;
    }
  • 相关阅读:
    分布式与集群的区别是什么?
    Java NIO:IO与NIO的区别 JAVA BIO与NIO、AIO的区别
    localStorage使用总结 JS 详解 Cookie、 LocalStorage 与 SessionStorage
    tomcat+nginx+redis实现均衡负载、session共享 存储过程的优缺点 HTTP、TCP、IP协议常见面试题
    高并发下的Java数据结构(List、Set、Map)
    [剑指offer] 31. 整数中1出现的次数(从1到n整数中1出现的次数)
    [剑指offer] 30. 连续子数组的最大和
    [剑指offer] 29. 最小的K个数
    [剑指offer] 28. 数组中出现次数超过一半的数字
    [leetcode] 51. N-Queens (递归)
  • 原文地址:https://www.cnblogs.com/moyiii-/p/7252715.html
Copyright © 2020-2023  润新知