Time Limit: 1000MS Memory Limit: 30000K

Description

The city consists of intersections and streets that connect them.

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

The first line of the input contains two integers: N and S, 1 <= N <= 100000, 1 <= S <= N. N is the total number of intersections; S is ordinal number of the snow plovers starting intersection. Intersections are marked with numbers 1...N.

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

Write to the output the minimal amount of fuel needed to clean all streets.

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]的更多相关文章

  1. poj 2324 Anniversary party(树形DP)

    /*poj 2324 Anniversary party(树形DP) ---用dp[i][1]表示以i为根的子树节点i要去的最大欢乐值,用dp[i][0]表示以i为根节点的子树i不去时的最大欢乐值, ...

  2. POJ 1655.Balancing Act 树形dp 树的重心

    Balancing Act Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14550   Accepted: 6173 De ...

  3. POJ 2342 - Anniversary party - [树形DP]

    题目链接:http://poj.org/problem?id=2342 Description There is going to be a party to celebrate the 80-th ...

  4. POJ - 3162 Walking Race 树形dp 单调队列

    POJ - 3162Walking Race 题目大意:有n个训练点,第i天就选择第i个训练点为起点跑到最远距离的点,然后连续的几天里如果最远距离的最大值和最小值的差距不超过m就可以作为观测区间,问这 ...

  5. POJ 2486 Apple Tree(树形DP)

    题目链接 树形DP很弱啊,开始看题,觉得貌似挺简单的,然后发现貌似还可以往回走...然后就不知道怎么做了... 看看了题解http://www.cnblogs.com/wuyiqi/archive/2 ...

  6. POJ 3162 Walking Race 树形DP+线段树

    给出一棵树,编号为1~n,给出数m 漂亮mm连续n天锻炼身体,每天会以节点i为起点,走到离i最远距离的节点 走了n天之后,mm想到知道自己这n天的锻炼效果 于是mm把这n天每一天走的距离记录在一起,成 ...

  7. poj 2342 Anniversary party 树形DP入门

    题目链接:http://poj.org/problem?id=2342 题意:一家公司有1 <= N <= 6 000个职工,现要组织一些职工参加晚会,要求每个职工和其顶头上司不能同时参加 ...

  8. 杭电OJ——1011 Starship Troopers(dfs + 树形dp)

    Starship Troopers Problem Description You, the leader of Starship Troopers, are sent to destroy a ba ...

  9. POJ 3162.Walking Race 树形dp 树的直径

    Walking Race Time Limit: 10000MS   Memory Limit: 131072K Total Submissions: 4123   Accepted: 1029 Ca ...

随机推荐

  1. Visual Studio 添加SVN插件

    这两天为了开发一个移动混合式的框架,被迫去学习去使用VisualStudio,这玩意当年离开校园就再也没用过了,再次看到感觉还是很眼熟...,这篇文件就简单说明下VS下怎么安装SVN插件吧: 1 首先 ...

  2. NYOJ 116 士兵杀敌 (线段树,区间和)

    题目链接:NYOJ 116 士兵杀敌 士兵杀敌(二) 时间限制:1000 ms  |  内存限制:65535 KB 难度:5 描写叙述 南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的 ...

  3. SpringMVC由浅入深day01_1springmvc框架介绍

    springmvc 第一天 springmvc的基础知识 课程安排: 第一天:springmvc的基础知识 什么是springmvc? springmvc框架原理(掌握) 前端控制器.处理器映射器.处 ...

  4. CentOS 6.3 + Subversion + Usvn 搭建版本管理服务器

    一. Subversion 简介 Subversion是一个自由,开源的版本控制系统.在Subversion管理下,文件和目录可以超越时空.Subversion将文件存放在中心版本库里.这个版本库很像 ...

  5. Flickr Hosts

    Test Page: http://www.flickr.com/help/test Hosts: 77.238.160.184 farm6.staticflickr.com 98.139.21.45 ...

  6. 使用dom4j解析xml为json对象

    import java.util.List; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j. ...

  7. WebService连接postgresql( 失败尝试)

     一.先进行postgresql的配置 1. 安装ODBC驱动 下载地址:http://www.postgresql.org/ftp/odbc/versions/msi/ 2. 打开 控制面板 -&g ...

  8. PowerDesigner快捷键【转】

    一般快捷键 快捷键 说明 F4 打开检查模型窗口,检查模型 F5 如果图窗口内的图改变过大小,恢复为原有大小即正常大小 F6 放大图窗口内的图 F7 缩小图窗口内的图 F8 在图窗口内中查看全部图内容 ...

  9. Google Analytics访问空白的解决方法

    在C:\Windows \System32 \drivers \etc下用记事本打开hosts文档 添加: 74.125.129.112 adwords.google.com 74.125.31.12 ...

  10. WP8.1学习系列(第八章)——透视Pivot设计指南

    在本文中 描述 应做事项和禁止事项 其他使用指南 相关主题 重要的 API Pivot class (XAML) PivotItem class (XAML) Windows Phone 应用:具有透 ...