hdu 4679 树的直径

  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 }
时间: 2024-11-08 21:49:10

hdu 4679 树的直径的相关文章

hdu 4607(树的直径)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4607 题解:给定一棵树,从树中的任意选一个顶点出发,遍历K个点的最短距离是多少?(每条边的长度为1) 算法分析: 首先如果k小于等于直径长度,那么答案为k−1;如果k大于直径长度,设直径长度为r,那么答案为r−1+(k−r)*2;树的直径:树上的最长简单路径; 代码: 1 #include <cstdio> 2 #include <cmath> 3 #include <cstri

hdu 4514(树的直径+并查集)

湫湫系列故事——设计风景线 Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 3930    Accepted Submission(s): 700 Problem Description 随着杭州西湖的知名度的进一步提升,园林规划专家湫湫希望设计出一条新的经典观光线路,根据老板马小腾的指示,新的风景线最好能建成环形,如果没有条件建成环形,

Warm up HDU - 4612( 树的直径 边双连通分量)

求在图中新建一条边后  剩下的最少的桥的数量..先tarjan求桥的数量..然后缩点..以连通分量为点建图  bfs求直径 最后用桥的数量减去直径即为答案 bfs求直径 https://www.cnblogs.com/WTSRUVF/p/9307517.html #include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <algorithm>

HDU 4612——Warm up——————【边双连通分量、树的直径】

Warm up Time Limit:5000MS     Memory Limit:65535KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4612 Description N planets are connected by M bidirectional channels that allow instant transportation. It's always possible to travel bet

(求树的直径)Warm up -- HDU -- 4612

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4612 给一个无向图, 加上一条边后,求桥至少有几个: 那我们加的那条边的两个顶点u,v:一定是u,v之间含有桥的数量最多,然后uv之间的桥都没了,剩下的就是要求的结果: 树的直径的定义刚好就是两个节点之间含有最多的边: 下面是有关树的直径的知识: 这个题目需要手动扩展,不然会爆栈,而且手动扩展的话要用C++提交. 代码: #pragma comment(linker, "/STACK:1024000

hdu 4612 Warm up 双连通缩点+树的直径

首先双连通缩点建立新图(顺带求原图的总的桥数,其实由于原图是一个强连通图,所以桥就等于缩点后的边) 此时得到的图类似树结构,对于新图求一次直径,也就是最长链. 我们新建的边就一定是连接这条最长链的首尾,这样就将原图的桥减少了直径个. #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<algorithm> #include<map&g

hdu 4123 Bob’s Race (树的直径相关+rmq+单调队列思想)

Bob's Race Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2115    Accepted Submission(s): 658 Problem Description Bob wants to hold a race to encourage people to do sports. He has got trouble

【HDU 4612 Warm up】BCC 树的直径

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4612 题意:一个包含n个节点m条边的无向连通图(无自环,可能有重边).求添加一条边后最少剩余的桥的数目. 思路:要想尽可能地消灭桥,那么添加的这条边一定是连通了最多的BCC. 所以首先进行双连通分量分解,并记录桥的数目:然后将同属一个BCC的点缩成一个,代之以block序号,以block序号为点将原图重构为一棵树. 最后求树的直径,桥的数目减去树的直径即为答案. 整体框架是学习了 http://w

hdu 4612 缩点 桥 树的直径

// http://acm.hdu.edu.cn/showproblem.php?pid=4612 // 大致题意: 给n个点和m条边,组成一个无向连通图,问  给我加一条边的权力(可连接任意两点)->让图的桥数量最小,输出此时桥的数量.(2<=N<=200000, 1<=M<=1000000) // 无向环里面的边没有桥,缩点,因为是连通图,所以缩完点后构成了一棵树,每条树边都是一个桥.要加一条边使得加完后图的桥数最小,结合上述,所以选择连接树直径的两端点.ans = 原先