POJ 1849 - Two - [DFS][树形DP]
Time Limit: 1000MS Memory Limit: 30000K
Description
Heavy snow covered the city so the mayor Milan gave to the winter-service a list of streets that have to be cleaned of snow. These streets are chosen such that the number of streets is as small as possible but still every two intersections to be connected i.e. between every two intersections there will be exactly one path. The winter service consists of two snow plovers and two drivers, Mirko and Slavko, and their starting position is on one of the intersections.
The snow plover burns one liter of fuel per meter (even if it is driving through a street that has already been cleared of snow) and it has to clean all streets from the list in such order so the total fuel spent is minimal. When all the streets are cleared of snow, the snow plovers are parked on the last intersection they visited. Mirko and Slavko don’t have to finish their plowing on the same intersection.
Write a program that calculates the total amount of fuel that the snow plovers will spend.
Input
Each of the next N-1 lines contains three integers: A, B and C, meaning that intersections A and B are directly connected by a street and that street's length is C meters, 1 <= C <= 1000.
Output
Sample Input
5 2
1 2 1
2 3 2
3 4 2
4 5 1
Sample Output
6
题意:
这个城市由节点和连接节点的街道组成,街道是双向的。
此刻大雪覆盖了这个城市,市长确定了一些街道要将它们清扫干净,这些街道保证所有的节点可以通过它们连通而且街道数目尽可能小。
现有两台相同的扫雪机S和M,它们的起点在同一个节点上。
所有被确定的街道必须至少被一台扫雪机经过,才能完成清扫任务,完成任务后S和M可以在原地停下,不必集合到某一点。
扫雪机的行进是需要耗费油量的(即使扫雪机行驶的是已被扫净的街道),因此扫雪机行进的总距离越小越好,你需要计算两台扫雪机完成任务的最小总行进距离。
题解:
我们知道,树都有一条直径,那么,
假设从这棵树上的某一点出发,遍历完所有的点之后回到该点需要走的边数是个固定值,为这棵子树的边数的两倍;
具体为什么,不带方向的树,任意一点都可作为树根,那么把选到的那一点作为树根,进行DFS模拟,很容易看出遍历完所有的点需要两倍边长总和;
但是根据我们题目的要求,其实遍历到最后剩下的一个点后,是没有必要返回的;
那么答案应该为边数的两倍减去始末这两点之间的距离,要使结果最优,必然要使这两点之间的距离尽可能的大,而树上两点之间的距离的最大值便为树的直径;
也就是说,如何寻找一条最短的路径遍历完一整棵树,应该以树的直径一端为起点,另一端为终点进行遍历。
回到本题,两辆车分担工作,那么就可以将两辆车的终点分别设为树直径的两个端点,而行进路线同上一模一样,那么这两辆车的起点在哪儿就无关紧要了:
①如果我们的起始点在直径上,那么很显然的,两辆车分别朝两个方向走,遇到直径上的分叉,就要花费分叉的总长*2的路程来遍历这些分叉,而直径上的边都只需要走一遍即可
②而如果我们的起始点不在直径上,那么他们两辆车只需要先把这个分叉遍历一遍,最后回到直径上,那么又可以按①的过程,两辆车朝两边走。
综上,我们就可以知道,这样需要走过的总路程 ans = "直径长度" + 2 * "所有分叉上边的长度总和",换句话说,就是ans = 2 * "所有边的长度总和" - "直径长度";
至于,求树的直径,我们可以有两种方法:
参考:http://blog.csdn.net/tc_to_top/article/details/47002255

首先是两次DFS的过程:
#include<cstdio>
#include<vector>
#define MAXN 100000+5
using namespace std;
struct Edge{
int u,v,w;
};
vector<Edge> adj[MAXN];
int n,s,d[MAXN],sum;
void dfs(int now,int par)
{
for(int i=;i<adj[now].size();i++)
{
Edge edge=adj[now][i];
int next=edge.v;
if(next==par) continue;
d[next]=d[now]+edge.w;
dfs(next,now);
}
}
int main()
{
while(scanf("%d%d",&n,&s)!=EOF)
{
sum=;
for(int i=;i<=n;i++) adj[i].clear();
for(int i=;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
sum+=w;
adj[u].push_back((Edge){u,v,w});
adj[v].push_back((Edge){v,u,w});
}
d[s]=;
dfs(s,-);
int max=,max_i;
for(int i=;i<=n;i++)
{
if(max<d[i])
{
max=d[i];
max_i=i;
}
}
d[max_i]=;
dfs(max_i,-);
int diameter=;
for(int i=;i<=n;i++) if(diameter<d[i]) diameter=d[i];
printf("%d\n",*sum-diameter);
}
}
至于树形DP的方法,思维其实和两次DFS异曲同工,通过DFS可以得到任何一个点的dp[i][0]和dp[i][1]:
dp[i][0]存储点i延伸出去所能达到的最远长度,dp[i][1]存储点i从另一完全不同的路线(意思是一条重合的边都不能有)延伸出去所能到达的最远长度(称其为次远长度);
那么显然,所有点中,只有在树直径上的那些个点的dp[i][0]+dp[i][1]是最大的,而此时dp[i][0]+dp[i][1]的值即为树的直径长度。
#include<cstdio>
#include<cstring>
#include<vector>
#define MAXN 100000+5
using namespace std;
struct Edge{
int u,v,w;
};
vector<Edge> adj[MAXN];
int n,s,sum,diameter;
int dp[MAXN][];
void dfs(int now,int par)
{
for(int i=;i<adj[now].size();i++)
{
Edge edge=adj[now][i];
int next=edge.v;
if(next==par) continue;
dfs(next,now);
if(dp[now][] < dp[next][]+edge.w) // ( "其某个孩子的最大"+"其与孩子的距离" ) > "最大" > "次大"
{
dp[now][] = dp[now][];
dp[now][] = dp[next][] + edge.w;
}
else if(dp[now][] < dp[next][]+edge.w) // "最大" > ( "其某个孩子的最大"+"其与孩子的距离" ) > "次大"
{
dp[now][] = dp[next][]+edge.w;
}
}
if(diameter<dp[now][]+dp[now][]) diameter=dp[now][]+dp[now][];
}
int main()
{
while(scanf("%d%d",&n,&s)!=EOF)
{
diameter=sum=;
for(int i=;i<=n;i++) adj[i].clear();
memset(dp,,sizeof(dp));
for(int i=;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
sum+=w;
adj[u].push_back((Edge){u,v,w});
adj[v].push_back((Edge){v,u,w});
}
dfs(s,-);
printf("%d\n",*sum-diameter);
}
}
POJ 1849 - Two - [DFS][树形DP]的更多相关文章
- poj 2324 Anniversary party(树形DP)
/*poj 2324 Anniversary party(树形DP) ---用dp[i][1]表示以i为根的子树节点i要去的最大欢乐值,用dp[i][0]表示以i为根节点的子树i不去时的最大欢乐值, ...
- POJ 1655.Balancing Act 树形dp 树的重心
Balancing Act Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 14550 Accepted: 6173 De ...
- POJ 2342 - Anniversary party - [树形DP]
题目链接:http://poj.org/problem?id=2342 Description There is going to be a party to celebrate the 80-th ...
- POJ - 3162 Walking Race 树形dp 单调队列
POJ - 3162Walking Race 题目大意:有n个训练点,第i天就选择第i个训练点为起点跑到最远距离的点,然后连续的几天里如果最远距离的最大值和最小值的差距不超过m就可以作为观测区间,问这 ...
- POJ 2486 Apple Tree(树形DP)
题目链接 树形DP很弱啊,开始看题,觉得貌似挺简单的,然后发现貌似还可以往回走...然后就不知道怎么做了... 看看了题解http://www.cnblogs.com/wuyiqi/archive/2 ...
- POJ 3162 Walking Race 树形DP+线段树
给出一棵树,编号为1~n,给出数m 漂亮mm连续n天锻炼身体,每天会以节点i为起点,走到离i最远距离的节点 走了n天之后,mm想到知道自己这n天的锻炼效果 于是mm把这n天每一天走的距离记录在一起,成 ...
- poj 2342 Anniversary party 树形DP入门
题目链接:http://poj.org/problem?id=2342 题意:一家公司有1 <= N <= 6 000个职工,现要组织一些职工参加晚会,要求每个职工和其顶头上司不能同时参加 ...
- 杭电OJ——1011 Starship Troopers(dfs + 树形dp)
Starship Troopers Problem Description You, the leader of Starship Troopers, are sent to destroy a ba ...
- POJ 3162.Walking Race 树形dp 树的直径
Walking Race Time Limit: 10000MS Memory Limit: 131072K Total Submissions: 4123 Accepted: 1029 Ca ...
随机推荐
- 高可用(HA)架构
http://aokunsang.iteye.com/blog/2053719 浅谈web应用的负载均衡.集群.高可用(HA)解决方案 http://zhuanlan.51cto.com/art/ ...
- Java从控制台接受输入字符
创建一个类,在该类的主方法中创建Scanner扫描起来封装System类的in输入流,然后提示用户输入身份证号码,并输入身份证号码的位数. 代码如下: import java.util.Scanner ...
- java命令行操作
一直使用eclipse操作java程序,但RMI程序需要命令行操作,故研究了下java的命令行操作. javac 用于编译.java文件,生成.class文件 假设文件夹dir下有pa.java和a. ...
- Git Step by Step – (8) Git的merge和rebase
前面一篇文章中提到了"git pull"等价于"git fetch"加上"git merge",然后还提到了pull命令支持rebase模式 ...
- IOPS性能指标
如何计算mysql的IOPS? qps 每秒处理的查询数tps 每秒处理的事务数IOPS,每秒磁盘进行的I/O操作次数 今天看到一篇文章说磁盘理论最大IOPS为200左右,我有两个疑问:1.MYSQL ...
- 【代码审计】JTBC(CMS)_PHP_v3.0 任意文件上传漏洞分析
0x00 环境准备 JTBC(CMS)官网:http://www.jtbc.cn 网站源码版本:JTBC_CMS_PHP(3.0) 企业版 程序源码下载:http://download.jtbc. ...
- MFC之自绘控件
在描绘MFC界面时,MFC自带的控件样式是绝对不满足界面的需求的. 所以我们就要在MFC自带控件基础上对控件样式进行重绘. 在采用自绘前界面样式 采用自绘后界面样式 是不是自绘控件后看起来正常了很多? ...
- C++ template —— 函数对象和回调(十四)
本篇是本系列博文最后一篇,主要讲解函数对象和回调的相关内容.函数对象(也称为仿函数)是指:可以使用函数调用语法进行调用的任何对象.在C程序设计语言中,有3种类似于函数调用语法的实体:函数.类似于函数的 ...
- (转载)JVM实现synchronized的底层机制
目前在Java中存在两种锁机制:synchronized和Lock,Lock接口及其实现类是JDK5增加的内容,其作者是大名鼎鼎的并发专家Doug Lea.本文并不比较synchronized与Loc ...
- 【MATLAB】评价二值分割结果的函数
根据PASCAL challenges的标准:intersection-over-union score,所写的matlab评价程序,处理二值图像. 其思想即分割结果与Ground Trueth的交集 ...