题意:

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

思路:

     方法有很多,最少有三种方法,我用两种方法做的,别的暂时没想到(太弱了);

     第一种:

            先求出来一颗最小树,然后枚举树上的边,枚举到每一条边的时候就假设把这条边删除了,然后分成两个集合,我们只要在这两个集合之间连一条边,肯定就是树了,那么怎么连呢,我们可以直接搜索两个集合中分别权值最大的那个点,假设连接这两条边,因为要就该边的权值/非该边的所有和最大,每次枚举相当于分母固定了(最小树 - 当前枚举的边),只要找到最大的分子就行了,所以在两个集合里面找最大的点.就这样遍历到最后,取得最大值就行了.

    第二种:

          第二种是和上面的想法相反的,是分子固定找分母,做法也是先找到一颗最小树,然后枚举所有边,当枚举该边的时候就假设该边就是那个特殊的边,那么权值分子就固定是边的两个点的权值,那么分子呢,分两种情况,如果当前枚举的边不是最小树上的边,那么加上这条边后就一定会形成环,我们既然要比值最大,而且还必须是棵树,那就必须在环上删除一条最大的边(不算当前这条边),如果当前的边是最小树上的边,那么就删除该边就行了,其实两种情况的写法都一样,分母都是 最小树 - 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\n" ,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\n" ,ans);

   }

   return 0;

}

      

         

         

      

   

   

   

 

hdu4081 最小树+DFS或者次小树的变形的更多相关文章

  1. POJ 1679 判断最小树是否唯一

    题意:       给你一个图,问你最小树是否唯一,唯一则输出最小数的权值,不唯一输出Not Unique! 思路:      题目问的是最小树是否唯一,其实也就是在问次小树是否等于最小树,如果等于则 ...

  2. Educational Codeforces Round 17

    Educational Codeforces Round 17 A. k-th divisor 水题,把所有因子找出来排序然后找第\(k\)大 view code //#pragma GCC opti ...

  3. cong

    Directions:  Study the following cartoon carefully and write an essay in which you should 1) descr ...

  4. hbase——b树,b+树,lsm树

    b树 b树,又叫做平衡多路查找树.一个m阶的b树的特性如下: 树中的每个节点,最多有m个子节点. 除了根节点之外,其他的每个节点至少有ceil(m/2)个子节点,ceil函数为取上限函数. 所有的叶子 ...

  5. vsCode安装todo插件

    使用过IDEA或者WebStrom的阿媛应该都知道他们都有一个TODO功能,方便我们跟踪注释,或者说是我们在项目代码里面所做的标记:但是如果你现在在使用vsCode,你会发现,没有TODO功能,幸好, ...

  6. POJ1679判断最小生成树的唯一性

    题意:      判断最小树是否唯一. 思路:      我用了两种方法,主要就是好久没敲了,找个水题练练手,第一种就是先一遍最小生成树,然后枚举最小生成树上的每一条边,然后取消这条边,在跑一遍最小生 ...

  7. hdu4756 最小树+树形dp

    题意:       给你一个完全图,让你在上面找到一颗最小树,然后问破坏这个最小树的某一条边后用其他边连接(要求最小)成新的树,然后输出破坏每一条边后最小树中最大的那个. 思路:       先跑出一 ...

  8. html5 canvas(小树姐的牛掰到爆了的作品)

    自从小树嫁了个牛逼的前端之后,canvas的境界超过我了!!! 小树demo 小编表示:这个境界,这个几何,让我有种跪舔的感觉... http://www.wow-trend.com/brand/in ...

  9. POJ2349二分+并查集,类似最小树的贪心

    题意:       给你n个点,你的任务是构建一颗通讯树,然后给你一个s表示可以选出来s个点两两通讯不花钱,就是费用是0,其他的费用就是两点的距离,有个要求就是其他的费用中最大的那个最小. 思路:   ...

随机推荐

  1. if...else和switch...case

    一.位运算 class Demo01 { public static void main(String[] args) { int a = 5; int b = 3; /* 0000 0101 |00 ...

  2. golang操作mysql2

    目录 Go操作MySQL 连接 下载依赖 使用MySQL驱动 初始化连接 SetMaxOpenConns SetMaxIdleConns CRUD 建库建表 查询 单行查询 多行查询 插入数据 更新数 ...

  3. [个人总结]pip安装tensorboard太慢

    在执行pip install语句的时候直接指定国内豆瓣的镜像源进行下载: pip install -i https://pypi.douban.com/simple 你想下载的包的名称 例如下载ten ...

  4. 循环单链表定义初始化及创建(C语言)

    #include <stdio.h> #include <stdlib.h> /** * 含头节点循环单链表定义,初始化 及创建 */ #define OK 1; #defin ...

  5. UML类图画法整理

    一 类图画法 1.类图的概念 显示出类.接口以及他们的静态结构和关系,用于描述系统的结构化设计. 2.类 类是对一组具有相同属性.操作.关系和语义对象的抽象,是面向对象的核心,包括名称.属性和方法.如 ...

  6. C# 8 - Nullable Reference Types 可空引用类型

    在写C#代码的时候,你可能经常会遇到这个错误: 但如果想避免NullReferenceException的发生,确实需要做很多麻烦的工作. 可空引用类型 Null Reference Type 所以, ...

  7. java例题_10小球 自由落体

    1 /*10 [程序 10 自由落体] 2 题目:一球从 100 米高度自由落下,每次落地后反跳回原高度的一半: 3 求它在 第 10 次落地时,共经过多少米? 4 第 10 次反弹多高? 5 */ ...

  8. SQL注入靶场实战-小白入门

    目录 SQL注入 数字型 1.测试有无测试点 2.order by 语句判断字段长,查出字段为3 3.猜出字段位(必须与内部字段数一致)(用union联合查询查看回显点为2,3) 4.猜数据库名,用户 ...

  9. PAT (Advanced Level) Practice 1006 Sign In and Sign Out (25 分) 凌宸1642

    PAT (Advanced Level) Practice 1006 Sign In and Sign Out (25 分) 凌宸1642 题目描述: At the beginning of ever ...

  10. 将Java编译为本地代码

    将Java编译为本地代码 通常Java程序的执行流程为:将Java代码编译为Byte Code(字节码),然后JVM执行引擎执行编译好的Byte Code.这是一种中间语言的特性,它的好处就是可以做到 ...