POJ 1849 Two(遍历树)
来源:互联网 发布:js鼠标滚动条事件 编辑:程序博客网 时间:2024/06/07 05:49
POJ 1849 Two(遍历树)
http://poj.org/problem?id=1849
题意:
有一颗n个结点的带权的无向树, 在s结点放两个机器人, 这两个机器人会把树的每条边都走一遍, 但是最后机器人不要求回到出发点. 问你两个机器人走的路总长之和的最小值是多少?
分析:
首先本题只要求出树的直径, 然后用树的总长sum*2-树的直径就是所求结果. 下面一步步来说明为什么是这样的.
1.假设只有1个机器人遍历树,且要求回到原点,它最少需要走多少路?
答: 它需要走树总长sum的两倍, 即每条树边它都要走两次才行. 这个结论画个图就明白了, 对于每条边, 机器人要走过该边, 之后还要从该边回去(不回来就不能回到出发点了). 所以自然是sum*2.
2.假设1问中的机器人遍历树,但是不要求它回到原点,那么它最少需要走多少路?
答: 最少需要走sum-[从出发点能走到最远的点的距离]. 在行走的过程中每个分叉, 它走过去,又走回来即可. 可以反证得出.
3.假设有两个机器人从s出发,遍历整个树且最终回到出发点.它们行走的最短距离是?
答: 树总长的两倍. 每个机器人都必须回到原点, 那么必然每条边至少要被走两次.
4.假设有两个机器人从s出发,遍历整个树且它们不需要回到出发点.它们行走的最短距离是?
答: 树总长的两倍-树的直径. 机器人出去不回来,则所走路径中有一条简单路径是可以只走一遍的,派出了两个点去遍历,也就是说有两条简单路径是可以直走一边的,我们要使这两条简单路径的总和尽可能的长,就转换为了树的最长路径问题了.
注意:上面第4种情况, 两个机器人从哪点出发都是没有任何区别的. 因为如果它们出发点不在树的直径上, 那么它们一定可以一起移动到树直径上的某个点上,然后分别朝树直径的两个方向走, 并且遍历它们走的树直径的所有分叉路两次.
AC代码:
#include<cstdio>#include<cstring>#include<algorithm>#include<queue>using namespace std;const int maxn=100000+5;//边结构struct Edge{ Edge(){} Edge(int to,int cost,int next):to(to),cost(cost),next(next){} int to; int cost; int next;}edges[maxn];int cnt=0;//总边数int head[maxn];//添加两条有向边void AddEdge(int u,int v,int cost){ edges[cnt]=Edge(v,cost,head[u]); head[u]=cnt++; edges[cnt]=Edge(u,cost,head[v]); head[v]=cnt++;}int dist[maxn];//返回从s能到达的最长点编号int BFS(int s){ int max_dist=0; int id=s; queue<int> Q; memset(dist,-1,sizeof(dist)); dist[s]=0; Q.push(s); while(!Q.empty()) { int u=Q.front(); Q.pop(); if(dist[u]>max_dist) max_dist=dist[id=u]; for(int i=head[u]; i!=-1; i=edges[i].next) { Edge &e=edges[i]; if(dist[e.to]==-1) { dist[e.to]=dist[u]+e.cost; Q.push(e.to); } } } return id;}int main(){ int n,s; while(scanf("%d%d",&n,&s)==2) { int sum=0;//树的总长 memset(head,-1,sizeof(head)); cnt=0; for(int i=1;i<=n-1;i++) { int u,v,cost; scanf("%d%d%d",&u,&v,&cost); sum+=cost; AddEdge(u,v,cost); } printf("%d\n",sum*2-dist[BFS(BFS(s))]); } return 0;}
- POJ 1849 Two(遍历树)
- POJ 1849 Two【树的直径+树的遍历】
- POJ 1849 Two(树的直径)
- POJ 1849 Two///树的直径
- POJ 1849 Two 树的直径
- poj 1849 Two
- POJ 1849 Two
- POJ 1849 Two
- POJ 1849 Two 笔记
- POJ 1849 Two(求树的直径)
- poj 1849 Two 树形dp好题
- poj 2255 二叉树遍历
- POJ - 2255 二叉树遍历
- POJ 1849 Two(树的直径--树形DP)(好题)
- POJ 1849 Two (树形dp 树的直径 两种方法)
- POJ 2255 二叉树遍历 已知前序遍历 中序遍历 求后序遍历
- poj 2738 Two Ends
- Poj 3320(two pointers)
- linux 下查看机器是cpu是几核的
- 每日算法(数组与字符串)
- 指针初识6(指针与多维数组)
- 第十周项目6-贪财的富翁
- 求小数的循环节
- POJ 1849 Two(遍历树)
- Java基础-将Bean属性值放入Map中
- using thymeleaf 之 th:each迭代循环
- 手写快速排序【随机数作基数】
- hdu 4771 Stealing Harry Potter's Precious(bfs+枚举)
- 中文分词实现——双向最大匹配
- 的个电饭锅
- [jbb0523整理]压缩感知中的数学知识:NP-hard问题
- 日语学习之新版初级标准日本语-6 吉田さんは来月中国へ