【DFS好题】BZOJ1999- [Noip2007]Core树网的核(数据加强版)

NOIP的数据好水,一开始有好几个错结果NOIP数据就水过了??

【题目大意】

求无根树的直径上一段不超过S长的链,使得偏心距最小。具体概念见原题

【思路】

首先明确几个性质:

(1)对于树中的任意一点,距离其最远的点一定是树的直径的某一端点。

(2)所有的直径是等价的,即任意一条所能求出的该最小偏心距相等。

于是我们可以用两次dfs求出直径。任取一个点找到离它最远的点r,再从r找到距离它最远的点l。l到r的路径就是直径。

显然在长度不超过S的情况下,链最长最好。在l到r上维护尽可能长的链,找到左右端点到直径做右端点的较大值的最小值。然后由链上各个点出发,找到不经过直径上的点抵达的其他点的最大深度。这个最大深度和之前的最小值中较大的就是答案。

为什么是整条直径上找最大深度,而不是在核上找呢?

显然,如果这个深度最深的点不是从核中的点,那么它到核的距离必定小于核的端点到直径端点的距离。所以如果有个节点到核的距离小于核的端点到直径端点的距离,那么它必定是从核上延伸出去的。

【错误点】

具体见程序。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int MAXN=500000+50;
 4 const int INF=0x7fffffff;
 5 struct edge
 6 {
 7     int to,len;
 8 };
 9 vector<edge> E[MAXN];
10 int n,s;
11 int l,r,dis[MAXN],f[MAXN],ban[MAXN];
12
13 void addedge(int u,int v,int w)
14 {
15     E[u].push_back((edge){v,w});
16     E[v].push_back((edge){u,w});
17 }
18
19 void init()
20 {
21     scanf("%d%d",&n,&s);
22     for (int i=1;i<n;i++)
23     {
24         int u,v,w;
25         scanf("%d%d%d",&u,&v,&w);
26         addedge(u,v,w);
27     }
28 }
29
30 void dfs(int u,int fa)
31 {
32     f[u]=fa;
33     for (int i=0;i<E[u].size();i++)
34     {
35         int to=E[u][i].to;
36         if (ban[to] || to==f[u]) continue;
37         dis[to]=dis[u]+E[u][i].len;
38         dfs(to,u);
39     }
40 }
41
42 void getd()
43 {
44     memset(ban,0,sizeof(ban));
45
46     l=1,r=1;
47     dfs(l,0);
48     for (int i=1;i<=n;i++) if (dis[i]>dis[r]) r=i;
49
50     l=r;
51     dis[r]=0;
52     dfs(r,0);
53     for (int i=1;i<=n;i++) if (dis[i]>dis[l]) l=i;
54 }
55
56 void solve()
57 {
58     int i=l,j=l,ans=INF;
59     for (;i;i=f[i])
60     {
61         while (f[j] && dis[i]-dis[f[j]]<=s) j=f[j];
62         ans=min(ans,max(dis[j],dis[l]-dis[i]));
63         //每次找到以i为一个端点的最接近于S的链
64         //比较两端点和直径端点的长度
65     }
66     for (i=l;i;i=f[i]) ban[i]=1;
67     //由于要找出不经过直径的最大深度,所以禁止访问直径上的点
68     for (int i=l;i;i=f[i]) dis[i]=0,dfs(i,f[i]);
69     //★★★★★★★注意这里i的父亲必须传进去f[i],否则就修改了直径
70     for (int i=1;i<=n;i++) ans=max(ans,dis[i]);
71     printf("%d",ans);
72 }
73
74 int main()
75 {
76     init();
77     getd();
78     solve();
79     return 0;
80 } 
时间: 2024-10-19 01:08:07

【DFS好题】BZOJ1999- [Noip2007]Core树网的核(数据加强版)的相关文章

[BZOJ1999][codevs1167][Noip2007]Core树网的核

试题描述 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边带有正整数的权,我们称T为树网(treenetwork),其中V, E分别表示结点与边的集合,W表示各边长度的集合,并设T有n个结点. 路径:树网中任何两结点a,b都存在唯一的一条简单路径,用d(a,b)表示以a,b为端点的路径的长度,它是该路径上各边长度之和.我们称d(a,b)为a,b两结点间的距离. 一点v到一条路径P的距离为该点与P上的最近的结点的距离: d(v,P)=min{d(v,u),u为路径P上的结

[bzoj1999]树网的核

从下午坑到网上..原来noip的数据真是太弱了,若干的地方写挂结果还随便过= = 最坑的就是网上有些题解没考虑周全...然而noip数据太弱了noip数据太弱了noip数据太弱了 第一步是找直径,用两次bfs(或者dfs,Linux下系统栈挺大的..)解决.找出其中一条直径就可以了,虽然蒟蒻不会证明但是看起来似乎挺有道理的 要看证明的话可以看这个题解:http://trinklee.blog.163.com/blog/static/238158060201411175015709/ 直径上的路径

noip2007 树网的核

P1099 树网的核 112通过 221提交 题目提供者该用户不存在 标签动态规划树形结构2007NOIp提高组 难度提高+/省选- 提交该题 讨论 题解 记录 题目描述 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W表示各边长度的集合,并设T有n个结点. 路径:树网中任何两结点a,b都存在唯一的一条简单路径,用d(a, b)表示以a, b为端点的路径的长度,它是该路径上各边

BZOJ1999 NOIP2007 洛谷P1099 P2491 SDOI 2011

Description: 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W表示各边长度的集合,并设T有n个结点. 路径:树网中任何两结点a,b都存在唯一的一条简单路径,用d(a, b)表示以a, b为端点的路径的长度,它是该路径上各边长度之和.我们称d(a, b)为a, b两结点间的距离. D(v, P)=min{d(v, u), u为路径P上的结点}. 树网的直径:树网中最长

Oil Deposits(poj 1526 DFS入门题)

http://poj.org/problem?id=1562 Oil Deposits Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 12595   Accepted: 6868 Description The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSurvComp wor

leetcode中关于树的dfs算法题

Validate Binary Search Tree Recover Binary Search Tree Symmetric Tree Same Tree Maximum Depth of Binary Tree Construct Binary Tree from Preorder and Inorder Traversal Construct Binary Tree from Inorder and Postorder Traversal Convert Sorted Array to

DFS搜索题素数环

素数环: 输入整数1,2,3,4,5,···,n组成一个环,使得相邻两个整数之和均为素数. 输出时从整数1开始逆时针排列.同一个环应恰好输出一次.n<=16. Sample: input: 6 output: 1 4 3 2 5 6 1 6 5 2 3 4 使用DFS搜索解释:素数环的第一个数为1,则选定第一个数为1,然后向下遍历所有数据,能够和前面一个数据组合相加成为素数的数就被数组记录下来. 知道判断到最后一个数字,然后检查它和第一个数相加是否为素数,若是就输出数组中记录的答案,不是就从头开

树网的核(codevs 1167)题解

[问题描述] 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W表示各边长度的集合,并设T有n个结点. 路径:树网中任何两结点a,b都存在唯一的一条简单路径,用d(a, b)表示以a, b为端点的路径的长度,它是该路径上各边长度之和.我们称d(a, b)为a, b两结点间的距离. D(v, P)=min{d(v, u), u为路径P上的结点}. 树网的直径:树网中最长的路径成为树

NOIP 2007树网的核

题目描述 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W表示各边长度的集合,并设T有n个结点. 路径:树网中任何两结点a,b都存在唯一的一条简单路径,用d(a, b)表示以a, b为端点的路径的长度,它是该路径上各边长度之和.我们称d(a, b)为a, b两结点间的距离. D(v, P)=min{d(v, u), u为路径P上的结点}. 树网的直径:树网中最长的路径成为树网的