1 /*
  2 题目大意:给n个点n-1条边的树,求删除哪条边时两个树中最大的直径与边权的乘积最小。
  3 树的直径(Diameter)是指树上的最长简单路。
  4 直径的求法:两遍BFS (or DFS)
  5 若删除的边不是直径上的那么花费为max_len*wi
  6 若删除的边是直径上的那么花费为max(dp[u][2],dp[v][2])*wi
  7 */
  8 #pragma comment(linker, "/STACK:16777216")
  9 #include <iostream>
 10 #include <cstdio>
 11 #include <cstring>
 12 #include <vector>
 13 using namespace std;
 14
 15 const int maxn=100005;
 16 int dep[maxn],ans[maxn],father[maxn],max_len;//ans下标对应边的编号
 17 int dp[maxn][3];//j=0存i节点的到子树中的最长路,j=1存次长路,j=2存直径
 18 bool vis[maxn];//标记是否为直径上的点
 19 inline int max(int a,int b){return a>b?a:b;}
 20 struct node
 21 {
 22     int id,w,v;
 23     node(int id=0,int w=0,int v=0):id(id),w(w),v(v){}
 24 };
 25 vector<node> f[maxn];
 26
 27 void dfs_dep(int u,int pre)//找最长路
 28 {
 29     for(int i=0;i<f[u].size();i++)
 30     {
 31         int v=f[u][i].v;
 32         if(v==pre) continue;
 33         dep[v]=dep[u]+1;
 34         father[v]=u;
 35         dfs_dep(v,u);
 36     }
 37     return ;
 38 }
 39
 40 void dfs(int u,int pre)
 41 {
 42     dp[u][0]=dp[u][1]=dp[u][2]=0;
 43     for(int i=0;i<f[u].size();i++)
 44     {
 45         int v=f[u][i].v;
 46         if(v==pre) continue;
 47         dfs(v,u);
 48         int temp=dp[v][0]+1;
 49         if(temp>dp[u][0])
 50         {
 51             dp[u][1]=dp[u][0];dp[u][0]=temp;
 52         }
 53         else if(temp>dp[u][1])
 54             dp[u][1]=temp;
 55         dp[u][2]=max(dp[u][2],dp[v][2]);//u在子树直径边上与不再直径边上
 56     }
 57     dp[u][2]=max(dp[u][2],dp[u][0]+dp[u][1]);//u在子树直径中与不再直径中
 58 }
 59
 60 void solve(int u,int pre)
 61 {
 62     for(int i=0;i<f[u].size();i++)
 63     {
 64         int v=f[u][i].v,id=f[u][i].id,w=f[u][i].w;
 65         if(v==pre) continue;
 66         solve(v,u);
 67         //在树的直径上
 68         if(vis[u] && vis[v])
 69             ans[id]=max(ans[id],w*dp[v][2]);
 70         else ans[id]=w*max_len;
 71     }
 72 }
 73
 74 int main()
 75 {
 76     int t,i,n,icase=0,a,b,w;
 77     scanf("%d",&t);
 78     while(t--)
 79     {
 80         scanf("%d",&n);
 81         for(i=1;i<=n;i++) f[i].clear();
 82         for(i=1;i<n;i++)
 83         {
 84             scanf("%d%d%d",&a,&b,&w);
 85             f[a].push_back(node(i,w,b));
 86             f[b].push_back(node(i,w,a));
 87         }
 88         int st,ed=1,temp;
 89         dfs_dep(ed,-1);
 90         for(i=1;i<=n;i++)
 91             if(dep[ed]<dep[i]) ed=i;
 92         dep[st=ed]=0;
 93         dfs_dep(st,-1);
 94         ed=st;
 95         for(i=1;i<=n;i++)
 96             if(dep[ed]<dep[i]) ed=i;
 97         max_len=dep[ed];
 98         memset(vis,0,sizeof(vis));
 99         father[st]=-1;temp=ed;
100         while(father[temp]!=-1)
101             vis[temp]=true,temp=father[temp];
102         memset(ans,0,sizeof(ans));
103         dfs(st,-1);solve(st,-1);
104         dfs(ed,-1);solve(ed,-1);
105         temp=1;
106         for(i=1;i<n;i++)
107             if(ans[i]<ans[temp]) temp=i;
108         printf("Case #%d: %d\n",++icase,temp);
109     }
110     return 0;
111 }

转载于:https://www.cnblogs.com/xiong-/p/4141895.html

hdu 4679 树的直径相关推荐

  1. hdu 4679 树状dp

    思路:我们其实只需要枚举每条边,求得最小值就行了. 先dfs算出每个节点作为根时,其子树的最长路径,以及进过该节点的最长,次长,第三长路径. 然后在次dfs枚举求出切断某条边,求出这条边的两个端点为子 ...

  2. hdu 4607 Park Visit 求树的直径

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4607 Claire and her little friend, ykwd, are travelli ...

  3. HDU - 4607 Park Visit (树的直径)

    http://acm.hdu.edu.cn/showproblem.php?pid=4607 题意 一颗n个顶点的树,现在只想访问其中k个,问最短路径长度为多少. 分析 首先,最短的路径当然是一条链. ...

  4. hdu 3721 树的最小直径

    题意:       给你一棵树,让你改变一条边,改变之后依然是一棵树,然后问你怎样改变才能让树的直径最短.这里的改变一条边指的是指把一条边长度不变,连在别的两个点上. 思路:       首先求出树的 ...

  5. HDU - 7009 树上游走(树的直径+容斥)

    题目链接:点击查看 题目大意:给一棵树,称一个点集 S 是好的当且仅当存在一个点,其到 S 中所有点的距离互不相同,求 |S| 的最大值和使得 |S| 最大的 S 的个数 题目分析:不难看出 ∣S∣| ...

  6. HDU - 4612 Warm up(边双缩点+树的直径)

    题目链接:点击查看 题目大意:给出一个由n个点和m条边构成的无向图,现在允许加一条边,使得整张图中桥的数量最少,求最少的桥的数量 题目分析:因为是要求桥,所以直接用tarjan边双缩点,将原图转换成一 ...

  7. 【HDU - 5886】Tower Defence(树的直径,思维,dp)

    题干: There was a civil war between two factions in Skyrim, a province of the Empire on the continent ...

  8. HDU 4607 Park Visit(树的直径)

    题目大意:给定一棵树,让求出依次访问k个点的最小花费,每条边的权值都为1. 思路:如果能一直往下走不回来,那么这个路径肯定是最小的,这就取决于给定的k,但是怎么确定这个能一直走的长度呢,其实这个就是树 ...

  9. F - Warm up - hdu 4612(缩点+求树的直径)

    题意:有一个无向连通图,现在问添加一条边后最少还有几个桥 分析:先把图缩点,然后重构图为一棵树,求出来树的直径即可,不过注意会有重边,构树的时候注意一下 *********************** ...

最新文章

  1. 如何让GAN生成更高质量图像?斯坦福大学给你答案
  2. 40多个漂亮的网页表单设计实例
  3. Python过滤掉numpy.array中非nan数据
  4. SQLserver2008高级查询语句应用实例
  5. three.js glb 多个_25万的预算,奔驰GLB、宝马X1、奥迪Q3该怎么选
  6. 2010年11月编程语言排行榜:手机里的代码
  7. 跨境电子商务独立站如何找到热门的利基市场
  8. 使用vuex和axios获取api数据
  9. Unix网络编程 chart
  10. 【Daily Scrum】12-25
  11. 集合类接口和类层次关系图
  12. ADO中最重要的对象有三个:Connection、Recordset和Command
  13. 【OpenCV学习笔记】【类型转换】一(IplImage和cv::Mat的类型相互转换)
  14. openai-gpt_GPT-3的不道德故事:OpenAI的百万美元模型
  15. 尼枚罗指数matlab,洛伦兹系统李雅普诺夫指数的MATLAB源代码
  16. 微信小程序客服消息配置 token 验证失败 微信无请求记录 问题现象的解决办法
  17. VSCode完美卸载
  18. 暴风酷播云二期配置_暴风酷播云 一期-N3160版: 硬件折解及安装Proxmox VE-服务器虚拟化系统...
  19. Android AOSP和Android-X86源码下载编译终极普法
  20. CMake中file的使用

热门文章

  1. imoocLinux环境变量配置文件笔记
  2. rwkj 1359 友元:两点距离
  3. 使用.Net图表开发工具JDash.Net添加组件
  4. 让所有中国人看了气氛的广东某学校捐款过程
  5. 17 | 案例篇:如何利用系统缓存优化程序的运行效率?
  6. 34丨关于Linux网络,你必须知道这些(下)
  7. s4-8 虚拟局域网
  8. 茅台防伪溯源服务器临时维护,如何使用茅台防伪溯源系统?能辨别茅台酒真假?...
  9. ChaosBlade:从混沌工程实验工具到混沌工程平台
  10. 还在为多集群管理烦恼吗?RedHat 和蚂蚁、阿里云给开源社区带来了OCM