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 ...
随机推荐
- SpringBoot------Eclipce配置Spring Boot
步骤一: 步骤二: 点击左下角Eclipse图标下的“Popular”菜单,选择Spring安装(已安装的插件在Installed中显示),一直按步骤确定就好了,如果中途下载超时什么的,就看看自己的网 ...
- NetBpm 组织架构(4)
大牛的杰作,赞一个 转自:NetBPM工作流的架构设计及实现浅析 读前的话:由于本文涉及内容颇多,若有地方读来不很明白,建议先跳过,整体上有个认识后,再回过头来理解.作者认识有限,若有错误,欢迎斧正: ...
- NetBpm 配置篇(2)
转载注明出处:http://www.cnblogs.com/anbylau2130/p/3877353.html 上一篇中介绍了Netbpm在IIS和CassiniWebServer服务器的安装 通过 ...
- ios开发之--[_NSInlineData objectForKeyedSubscript:]
reason: '-[_NSInlineData objectForKeyedSubscript:]: unrecognized selector sent to instance 0x7fa2049 ...
- ckeditor 添加插件
官方插件包列表:https://ckeditor.com/cke4/addons/plugins/all 添加插件方法: 1)下载插件包(如果插件包有依赖其他插件,则依赖包也需要下载) 2)解压插件包 ...
- MongoDB(六)-- 集群搭建
一.集群介绍 sharding通过将数据集分布于多个也称作分片(shard)的节点上来降低单节点的访问压力.每个分片都是一个独立的数据库,所有的分片组合起来构成一个逻辑上的完整意义的数据库.因此,分片 ...
- Unity使用OpenGL绘制经纬线圈
using System.Collections; using System.Collections.Generic; using UnityEngine; public class LatLonGr ...
- [Ubuntu] 如何设置静态 IP 和 DNS
编辑 /etc/network/interfaces 来设置 IP 和 DNS 解析服务器: # interfaces() ) and ifdown() auto lo iface lo inet l ...
- codeforces水题100道 第二十六题 Codeforces Beta Round #95 (Div. 2) A. cAPS lOCK (strings)
题目链接:http://www.codeforces.com/problemset/problem/131/A题意:字符串大小写转换.C++代码: #include <cstdio> #i ...
- Android学习之DatePicker和TimePicker
在Android开发的应用程序中,通常都会有时间和日期选择的需求,下面就对日期选择控件DatePicker和时间选择控件TimePicker的基本使用方法进行介绍: DatePicker ...