UVa 11695 树的直径 Flight Planning

题意:

给出一棵树,删除一条边再添加一条边,求新树的最短的直径。

分析:

因为n比较小(n ≤ 2500),所以可以枚举删除的边,分裂成两棵树,然后有这么一个结论:

合并两棵树后得到的新树的最短直径为:

这两棵树一定是这样合并的,分别取两棵树直径的中点,然后将其连接起来。这样新树的直径才是最短的。

所以在找直径的同时还要记录下路径,方便找到中点。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <vector>
  5 using namespace std;
  6
  7 const int maxn = 2500 + 10;
  8
  9 int n;
 10
 11 struct Edge
 12 {
 13     int u, v, nxt;
 14     bool del;
 15 };
 16
 17 Edge edges[maxn * 2];
 18 int ecnt;
 19 int head[maxn];
 20
 21 void AddEdge(int u, int v)
 22 {
 23     Edge& e = edges[ecnt];
 24     e.u = u;
 25     e.v = v;
 26     e.nxt = head[u];
 27     e.del = false;
 28     head[u] = ecnt++;
 29 }
 30
 31 int pre[maxn];
 32 int len, id;
 33 void dfs(int u, int fa, int dep)
 34 {
 35     pre[u] = fa;
 36     if(dep > len) { len = dep; id = u; }
 37     for(int i = head[u]; ~i; i = edges[i].nxt)
 38     {
 39         if(edges[i].del) continue;
 40         int v = edges[i].v;
 41         if(v == fa) continue;
 42         dfs(v, u, dep + 1);
 43     }
 44 }
 45
 46 int mid;
 47
 48 int diameter(int u)
 49 {
 50     id = u;
 51     len = 0;
 52     dfs(u, 0, 0);
 53     int s = id;
 54     len = 0;
 55     dfs(s, 0, 0);
 56
 57     mid = id;
 58     for(int i = 0; i < len / 2; i++) mid = pre[mid];
 59
 60     return len;
 61 }
 62
 63 int main()
 64 {
 65     int T; scanf("%d", &T);
 66     while(T--)
 67     {
 68         scanf("%d", &n);
 69         memset(head, -1, sizeof(head));
 70         ecnt = 0;
 71
 72         for(int u, v, i = 1; i < n; i++)
 73         {
 74             scanf("%d%d", &u, &v);
 75             AddEdge(u, v); AddEdge(v, u);
 76         }
 77
 78         int ans = 10000000;
 79         int del_u, del_v, add_u, add_v;
 80
 81         for(int i = 0; i < ecnt; i += 2)
 82         {
 83             Edge& e = edges[i];
 84             edges[i].del = true;
 85             edges[i^1].del = true;
 86
 87             int d1 = diameter(e.u), tu = mid;
 88             int d2 = diameter(e.v), tv = mid;
 89             int d3 = (d1 + 1) / 2 + (d2 + 1) / 2 + 1;
 90
 91             d1 = max(max(d1, d2), d3);
 92             if(d1 < ans)
 93             {
 94                 ans = d1;
 95                 del_u = edges[i].u;
 96                 del_v = edges[i].v;
 97                 add_u = tu;
 98                 add_v = tv;
 99             }
100
101             edges[i].del = false;
102             edges[i^1].del = false;
103         }
104
105         printf("%d\n%d %d\n%d %d\n", ans, del_u, del_v, add_u, add_v);
106     }
107
108     return 0;
109 }

代码君

时间: 2024-11-03 21:58:49

UVa 11695 树的直径 Flight Planning的相关文章

UVA 11695 Flight Planning 修改一条边使得树的直径最短

题目链接:点击打开链接 题意: 给定n(n<=2500) 节点的一棵树 删除一条边再加入一条边使得树的直径最短. 思路:首先枚举删除的那条边, 然后计算出删除后的2棵子树各自的重心 则新建的边一定是重心的连线. 而新的直径要么是在某个子树中,要么是两个子树间. #include <cstdio> #include <algorithm> #include <string.h> #include <queue> #include <cstring&

UVa 10308 Roads in the North 树的直径

题目来源:UVa 10308 Roads in the North 题意:求距离最远的2点之间的距离 思路:裸的树的直径 或者树形DP #include <cstdio> #include <cstring> #include <queue> using namespace std; const int maxn = 100010; struct node { int to, w; node(){} node(int to, int w): to(to), w(w) {

poj 1985 Cow Marathon 【树的直径】

题目:poj 1985 Cow Marathon 题意:给出一个树,让你求树的直径. 分析: 树的直径:树上两点之间的最大距离. 我们从任意一点出发,BFS一个最远距离,然后从这个点出发,在BFS一个最远距离,就是树的直径. AC代码: /* POJ:1985 Cow Marathon 2014/10/12/21:18 Yougth*/ #include <cstdio> #include <iostream> #include <algorithm> #include

poj1849(求树的直径)

题目链接:http://poj.org/problem?id=1849 题意:有一颗n个结点的带权的无向树, 在s结点放两个机器人, 这两个机器人会把树的每条边都走一遍, 但是最后机器人不要求回到出发点. 问你两个机器人走的路总长之和的最小值是多少? 分析:如果从某点出发遍历完一棵树再回来,那么所有边都会走两遍,而从某点有两个机器人出发去遍历,因为不用回来,所以最后那两个人距离越远越好,可以从树的直径上某个点背道而驰,那么这段距离(树的直径)只走了一遍,其他的要走两遍,所以ans=sum*2-l

SDUT OJ 3045 迷之图论 (树的直径)

题目地址:SDUT OJ 3045 这题比赛的时候想的差不多..但是总是觉得不对..写了一次就没再写,然后删了..当时没想到的是第二次求出来的就是最长链..当时想到的两次bfs找最大值(这一种方法其实结果也对..TAT..),还有找到点后在回溯减去重点等等..但总觉得好像都不太对...赛后才知道这题原来是树的直径.....牡丹江区域现场赛的时候遇到过,不过赛后也没看... 找树的直径的方法其实就是先任取一点进行bfs,找到最远的一点,这时最远的一点肯定是最长链端点之一,然后再从这一最远点开始bf

hdu4612 无向图中任意添加一条边后使桥的数量最少 / 无向图缩点+求树的直径

题意如上,含有重边(重边的话,俩个点就可以构成了边双连通). 先缩点成树,在求数的直径,最远的连起来,剩下边(桥)的自然最少.这里学习了树的直径求法:第一次选任意起点U,进行bfs,到达最远的一个点v(level最深)该点必然是树的直径的一个端点,,再从该点出发,bfs,到最深的一点,该点深度就是直径.(证明:先假设u,是直径上一点,S,T是直径的端点,设v!=t,则有(V,U)+(U,S)>(T,U)+(U,S),矛盾,故t=v:若u不是直径上一点,设u到直径上的一点为x,同理易证. 最后 缩

ZOJ Problem Set - 3820 Building Fire Stations 【树的直径 + 操作 】

题目:problemId=5374" target="_blank">ZOJ Problem Set - 3820 Building Fire Stations 题意:给出n个点,n-1条边的一棵树.然后要在两个点上建立两个消防站.让全部点的到消防站最大距离的点的这个距离最小. 分析:首先先求这个树的直径.然后在树的直径的中点处把树分成两棵树.然后在把两棵树分别取中点的最大值就是ans值. 这个题目数据有点水了感觉... AC代码: #include <cstdi

BDFZOI 树的直径

提交次数:2 涉及知识:基础图论/BFS 描述 一棵树T的"直径"定义为结点两两间距离的最大值.给定带权树T,求T的直径长度. 输入 第一行包含2个整数N.M,表示图中共有N个结点和M条无向边.(N <= 5000,M<n)接下来M行,每行包含3个整数{u,v,w},表示有一条无向边连接结点u.v*输入保证是无环图输出一个整数,代表直径长度 样例输入 4 31 2 12 3 22 4 3 样例输出 5 代码: 1 #include<iostream> 2 #in

codeforces GYM 100114 J. Computer Network 无相图缩点+树的直径

题目链接: http://codeforces.com/gym/100114 Description The computer network of “Plunder & Flee Inc.” consists of n servers and m two-way communication links. Two servers can communicate either through a direct link, or through a chain of links, by relayi