zoukankan      html  css  js  c++  java
  • hdu4081 最小树+DFS或者次小树的变形

    题意:
          给你一个全图,在里面找到一棵树,这棵树最多只有一条边可以不是最小树(也可以是), 要求 那对特殊的边的两个权值/除了这条边其他边的和最大.


    思路:
         方法有很多,最少有三种方法,我用两种方法做的,别的暂时没想到(太弱了);
         第一种:
                先求出来一颗最小树,然后枚举树上的边,枚举到每一条边的时候就假设把这条边删除了,然后分成两个集合,我们只要在这两个集合之间连一条边,肯定就是树了,那么怎么连呢,我们可以直接搜索两个集合中分别权值最大的那个点,假设连接这两条边,因为要就该边的权值/非该边的所有和最大,每次枚举相当于分母固定了(最小树 - 当前枚举的边),只要找到最大的分子就行了,所以在两个集合里面找最大的点.就这样遍历到最后,取得最大值就行了.
        第二种:
              第二种是和上面的想法相反的,是分子固定找分母,做法也是先找到一颗最小树,然后枚举所有边,当枚举该边的时候就假设该边就是那个特殊的边,那么权值分子就固定是边的两个点的权值,那么分子呢,分两种情况,如果当前枚举的边不是最小树上的边,那么加上这条边后就一定会形成环,我们既然要比值最大,而且还必须是棵树,那就必须在环上删除一条最大的边(不算当前这条边),如果当前的边是最小树上的边,那么就删除该边就行了,其实两种情况的写法都一样,分母都是 最小树 - max(u ,v),max(u ,v)是树上u,v,之间最长的边,
    可以在枚举前搜索一遍求出来树上任意两点之间的最长边(时间是o(n^2));就这样遍历到最后取最小就行了.....


    我的两个解法都跑了900多,原因是最小树用的K求的,其实应该用P求会快很多,因为P是针对稠密图的,后来的4756 用K就过不去,必须用P + 树形dp 优化.




    最小树 + DFS


    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>


    using namespace std;


    typedef struct
    {
       int x ,y ,w;
    }NODE;


    typedef struct
    {
       int to ,next;
    }STAR;


    typedef struct
    {
       int a ,b;
       double x;
    }EDGE;


    NODE node[1100];
    EDGE edge[1100 * 1100 /2];
    STAR E[1100*2];
    int list[1100] ,tot;
    int mer[1100] ,MAX;
    int mk[1100*2];
    bool mark_dfs[1100];


    int finds(int x)
    {
       if(x == mer[x])
       return x;
       mer[x] = finds(mer[x]);
    }


    void add(int a ,int b)
    {
       E[++tot].to = b;
       E[tot].next = list[a];
       list[a] = tot;
    }


    bool camp(EDGE a ,EDGE b)
    {
       return a.x < b.x;
    }






    void DFS(int s ,int w)
    {
       if(MAX < w)
       MAX = w;
       for(int k = list[s] ;k ;k = E[k].next)
       {
          int to = E[k].to;
          if(mark_dfs[to]) continue;
          mark_dfs[to] = 1;
          DFS(to ,node[to].w);
       }
    }


    int main ()
    {
       int t ,n ,i ,j;
       scanf("%d" ,&t);
       while(t--)
       {
          scanf("%d" ,&n);
          for(i = 1 ;i <= n ;i ++)
          scanf("%d %d %d" ,&node[i].x ,&node[i].y ,&node[i].w);
          int tmp = 0;
          for(i = 1 ;i <= n ;i ++)
          for(j = i + 1 ;j <= n ;j ++)
          {
             int xx = node[i].x - node[j].x;
             int yy = node[i].y - node[j].y;
             double dis = sqrt(xx * xx * 1.0 + yy * yy * 1.0);
             edge[++tmp].a = i;
             edge[tmp].b = j;
             edge[tmp].x = dis;
          }
          
          memset(list ,0 ,sizeof(list));
          tot = 1;
          double sum = 0;
          sort(edge + 1 ,edge + tmp + 1 ,camp);
          int mkt = 0;
          for(i = 1 ;i <= n ;i ++)mer[i] = i;
          
          for(i = 1 ;i <= tmp ;i ++)
          {
             int x = finds(edge[i].a);
             int y = finds(edge[i].b);
             if(x == y) continue;
             mer[x] = y;
             sum += edge[i].x;
             add(edge[i].a ,edge[i].b);
             add(edge[i].b ,edge[i].a);
             mk[++mkt] = i; 
          } 
          double ans = 0;
          for(i = 1 ;i <= mkt ;i ++)
          {
             int ii = mk[i];
             int a = edge[ii].a;
             int b = edge[ii].b;
             MAX = node[a].w;
             memset(mark_dfs ,0 ,sizeof(mark_dfs));
             mark_dfs[a] = mark_dfs[b] = 1;
             DFS(a ,node[a].w);
             int m1 = MAX;
             memset(mark_dfs ,0 ,sizeof(mark_dfs));
             mark_dfs[a] = mark_dfs[b] =1;
             MAX = node[b].w;
             DFS(b ,node[b].w);
             int m2 = MAX;
             
             double aa = (m1 + m2) * 1.0 / (sum - edge[ii].x);
             if(ans < aa)
             ans = aa;
          }
          printf("%.2lf " ,ans);
       }
       return 0;
    }




    有点像次小生成树


    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>


    #define N (1000 + 100)


    using namespace std;


    typedef struct
    {
       int x ,y ,w;
    }NODE;


    typedef struct
    {
       int a ,b;
       double x;
    }EDGE;


    typedef struct
    {
       int to ,next;
       double dis;
    }STAR;


    NODE node[N];
    EDGE edge[N*N/2];
    STAR E[N*2];


    int list[N] ,tot;
    int mark_dfs[N];
    double maxe[N][N];
    int mer[N];


    void add(int a, int b ,double c)
    {
       E[++tot].to = b;
       E[tot].dis = c;
       E[tot].next = list[a];
       list[a] = tot;
    }


    int finds(int x)
    {
       if(x == mer[x]) return x;
       return mer[x] = finds(mer[x]);
    }


    bool camp(EDGE a ,EDGE b)
    {
       return a.x < b.x;
    }


    double maxx(double x ,double y)
    {
       return x > y ? x : y;
    }


    void dfs_max(int s ,double nowmax ,int oo)
    {
       for(int k = list[s] ;k ;k = E[k].next)
       {
          int to = E[k].to;
          if(mark_dfs[to]) continue;
          mark_dfs[to] = 1;
          maxe[oo][to] = maxx(nowmax,E[k].dis);
          dfs_max(to ,maxx(nowmax,E[k].dis),oo);
       }
       return;
    }


    int main ()
    {
       int t ,n ,i ,j;
       scanf("%d" ,&t);
       while(t--)
       {
          scanf("%d" ,&n);
          for(i = 1 ;i <= n ;i ++)
          scanf("%d %d %d" ,&node[i].x ,&node[i].y ,&node[i].w);
          int tmp = 0;
          for(i = 1 ;i <= n ;i ++)
          for(j = i + 1 ;j <= n ;j ++)
          {
             int xx = node[i].x - node[j].x;
             int yy = node[i].y - node[j].y;
             double dis = sqrt(xx * xx * 1.0 + yy * yy * 1.0);
             edge[++tmp].a = i;
             edge[tmp].b = j;
             edge[tmp].x = dis;
          }
          
          sort(edge + 1 ,edge + tmp + 1 ,camp);
          memset(list ,0 ,sizeof(list));
          tot = 1;
          double T_sum = 0;
          for(i = 1 ;i <= n ;i ++) mer[i] = i;
          for(i = 1 ;i <= tmp ;i ++)
          {
             int a = edge[i].a;
             int b = edge[i].b;
             int x = finds(a);
             int y = finds(b);
             if(x == y) continue;
             mer[x] = y;
             T_sum += edge[i].x;
             add(a ,b ,edge[i].x);
             add(b ,a ,edge[i].x);
          }
          
          for(i = 1 ;i <= n ;i ++)
          {
             memset(mark_dfs ,0 ,sizeof(mark_dfs));
             mark_dfs[i] = 1;
             dfs_max(i ,0 ,i);
          }
          
          double ans = 0;      
          
          for(i = 1 ;i <= tmp ;i ++)
          {
             int a = edge[i].a;
             int b = edge[i].b;
             double now;
             now = 1.0 * (node[a].w + node[b].w) / (T_sum - maxe[a][b]);
             if(ans < now) ans = now;
          }
          
          printf("%.2lf " ,ans);
       }
       return 0;
    }
          
             
             
          
       


















       
       








     









  • 相关阅读:
    ffmpeg mp4 视频输出为 aac 的命令
    git操作远程分支
    Linux (openSUSE 15.3 ) server ssh 可以使用,sftp无法使用
    小小思考题
    Linux 命令介绍
    2021 年 如何使用VMware 安装 ubuntu 7.04 虚拟机, 配置 apt 源
    Linux 下 命令行 使用浏览器
    oracle.cmd
    Sqlcmd
    vue eslint 配置使用
  • 原文地址:https://www.cnblogs.com/csnd/p/12063275.html
Copyright © 2011-2022 走看看